WWDC2001 Session 140
Transcript
Kind: captions
Language: en
surprised more people than I thought
would survive till this time on Friday
thanks to the marquee decide we're here
to talk about the colonel at 3:30 on
Friday no exciting demos to give it's
just me you and hopefully we can cover
some topics that you guys are really
concerned about so let's get this thing
going here
where is it up there it is
okay it's over here so what are you
going to learn today well the main thing
you're going to learn is what the basic
colonel services are that are available
to you as programmers you're also going
to learn some of the layering that goes
on above those services inside of our
system one of the things that you know
we've been able to talk about for the
last few years here at WWDC is you know
this really cool kernel technology we
have this year part of the message is
yeah we have really cool technology
don't use it right so how are you gonna
use it well you're going to use the
layers that are built above it you're
gonna mostly be writing Carbon
applications or cocoa applications your
some of you are going to be writing BSD
applications and wrapping them as you
just saw right to give them the user
experience of a higher-level application
right and we want to show you how some
of those services are are layered above
ours what you're going to learn is you
know when it's safe to directly call
some of our services right and when it's
not safe to call some of our service
what those higher-level services are
that are available to you through the
hire frameworks right to use those
instead all right
and the one of the key things that that
this session is going to teach you is
all right although you're not going to
be directly programming to very many of
our services in the kernel all right
when it comes time to do debugging right
you're going to have to know what's
happening at those lower levels of the
system because the debuggers tend to
jump you in at some of the lowest levels
and you have to work your way back up
right and so if you don't know how a
thread is tied to some of the higher
level services then you're going to be
in trouble
alright again the same thing when you're
trying to tune your application right
you have to understand how everything is
put together how the low level services
are used by the frameworks that you're
writing to in order to get the correct
performance characteristics that you're
looking for what you're not going to
learn here right we're not going to talk
about how to build file system cats
right there was another session right a
lot of people come to the kernel session
saying great I'm gonna learn about all
about how to program in the kernel well
you're gonna learn about the services we
provide and some of those are available
to catch traders as well but then
they're rapid in a whole different set
of services some obscuring some of ours
promoting some of their own we're not
here just specifically to talk about how
to write one of those right nor are we
here to talk about how to write a
networked kernel extension the
networking sessions covered most of that
and in general we're not here to talk
about how to write in the program in the
kernel alright that while a lot of this
applies the same services are available
in the kernel again you're going to tend
to be in one of those specialized
environments either an i/o kit extension
or a filesystem extension or potentially
and network text and when you're in each
of those environments the view on these
services is different you can do some of
these things you can't do some of these
things that we're going to talk about
and some of the in kernel programming
environments access to these services
are spelled a little bit differently or
take a few different parameters we're
not going to get into those right so
who's who would this book before then
this session right and it's for all
those people who are out there writing
applications today right that they need
to understand how to get the most out of
your program and the kernel services
that it's using will tell you how to get
the best performance and how to
understand all of that is what we're
here for
same thing text developers you may learn
a little bit but you're not going to
learn the details of how to do your work
and power users I mean when you run some
of the performance tools hopefully some
of you made it to the performance
section
performance tool section you're going to
see a lot of things going on in the
system right it helps to understand how
they're put together with the
lower-level services where Darwin is the
lowest level of Mac os10
everything that happens in Mac OS 10 to
some extent or another is mitigated
managed controlled by the Darwin layer
and in the Darwin layer right the kernel
part is the most critical part okay so
some of the general truths about being
in a Mac OS 10 application the first is
that every application that's a native
application in Mac OS 10 is a bsd
process alright it's not that some of
them are some of them aren't if you can
see them if they're an application you
can see them and manage them and control
them as BSD processes and because of the
way we implemented our kernel most
beasts of all processes are actually
mock tasks as well so inside of the
darwin kernel there's a layering of mock
and BSD and so every process is a mock
task it owns and controls a mock task
right and one of the things you're also
going to notice and be very tempted by
is the fact that the API is for all of
these different layers tend to be
available everywhere right you know if
you happen to be writing carbon CFM
application will then maybe not
everywhere but other than that you look
at the headers and you look at the
frameworks and there's a lot of api's
available to you right and one of the
things you have to do is is try to stick
to the highest level service that you
can for what programming environment
you're in use the services available
there they tend to map on to the lower
level services right and if you stick to
those you're going to be much better off
alright so what you've seen probably a
few times already today is this picture
of the Darwin kernel right where it
talks about file systems and networking
and and the i/o kit drivers that are
available and that you can write well
we're not really here to talk about
those bubbles that are there
here to talk about the background
everything else right the services that
the kernel provides that lets those
things and all the applications do what
they have to do right and again you've
traditionally seen this division of the
mach kernel versus the bsd part of the
kernel right we tend to think of those
as while there is a distinction and we
try to keep the formal layering there
right what we're concerned about is the
services that the kernel provides to you
as developers and how to make those
services the best the best matching to
the semantics of the higher-level
applications that we can write and so we
tend to say well we don't have these
distinctions right what we have is you
know one kernel that provides these
services in a layered fashion right and
the basic services are process
management threading scheduler file
management not necessarily the file
systems itself but everything that the
file systems use in order to interact
with the rest of the system and managing
files virtual memory inter process
communication and security so why don't
we start digging through some of these
things oh wait first that's right I
forgot where'd all these things come
from
right well the kernel is actually a
collection of technologies from
essentially three groups of places the
Mach 3o provides the foundation for a
lot of what goes on in the kernel
especially virtual memory scheduling and
IPC the the bsd portion the main bsd
portion of our code was picked up from
the for for lights project right and
that gives us a process model our
scheduling our file access and then we
picked up most of the networking code
from various flavors of freebsd right so
let's dig in and start talking about
process management in darwin right at
the very fundamental level every process
is a mock task right and every
application is a process so at the very
lowest level you have a mocktail
a mock task is the unit of resource
ownership as far as mock is concerned
right every task owns threads it
controls them
it has virtual memory space and is
managed through that mock task and it
has a port namespace to collect all the
IPC rights that are usable by that task
right and so traditionally you can
create tasks you can spend them and
resume them and create new threads in
them and get all kinds of information
about them
you can also one of the things people
tend to do is create exception handlers
for them right so that you can catch
exceptions that happen in a task and
process those and you can also get death
a notification and be told when certain
tasks that you have the handle to go
away well that's a nice set of services
right but typically you won't be able to
use those directly I mean you actually
can create a mock task all by itself in
the system but you can't manage it right
it's just this free-floating entity that
no one else can see you snip you late so
it's highly discouraged to ever create a
mock task all by itself right instead
you would tend to create a BST process
and you do that through the standard BST
api's you know v4 exact right create
them and destroy them you'd go ahead and
exit but the the BST process gives you
these additional resources
to go along with your task besides
giving you the ability to manage them
and name them right they give you the
signal handlers they give you file
descriptors they give you a whole
collection of resources and what happens
is when you when you have a bsd process
right and you go look at the mock tasks
KPIs that are available right a whole
bunch of them go away you if you try to
terminate a mock task that actually is
part of a bsd process that'll just
return you an error because the bsd part
of the system doesn't have a chance to
clean up and do the management that it
would do right and so we don't allow
that to happen of similarly creating new
ones right we don't allow you to do that
or
we prefer you not do that right
everything else is risky you can go
ahead and create exception handlers you
can go ahead and get info on the process
itself or the task itself or get a list
of threads or control threads create
threads right but you shouldn't do
anything else with the task right but
again a lot of you will not be
programming BSD processes you're
actually going to be programming
applications out at the higher level
right either carbon cocoa Java whatever
right and they add additional set of
resources an additional set of API is
for managing them actually many sets of
API is for managing it one of the things
that happens when you create those
higher-level applications is they all
talk to a common process management
service that's a part of the core
service core services in the system and
it does all of the management for you
and so you tend that's how you get
things that pop up in actually right
when you're looking at the tools that
are available at that level right you
have the doc and you have forced quit
and all those things CPS the core
process service is the thing that lets
you manage processes and the larger
applications all register with that our
process viewer will actually let you
view and inter SPECT just be of any bsd
process in the system the same with top
and PS and if you really want to see
what's going on down at the the lower
levels right you can use z print which
is a tool that talks to the kernels zone
management system and will basically
print out statistics on how many of
every kind of resource that the kernel
has and in those list is all of the mock
services and the mock resources that are
available so you'll see how many mocked
asks how many mock threads are being
managed as well and so you can actually
see and inspect some of the mock level
resources with that tool so this is how
you manage processes and handle
exceptions and all of that is all at
this level one of the things you have to
be very careful about is although BSD
processes have limits on the number of
threat or the number
open files and a lot of the other
resources that are available to you one
of the things that's not implemented in
the kernel that shipped was ten point oh
right is any ability to limit the
resource allocations at the MOC level so
any thread can go ahead and allocate
these resources right and we don't have
any limits on the amount of those
resources you can go ahead and allocate
and so if you have a runaway process
right that's just leaking a port or
leaking some kernel resource over and
over and over and over again right over
time the application may die that's
certainly one outcome that might might
come from this but another outcome from
that particular problem is that it may
actually just lock up the system and
eventually panic the system because
you've ran out of kernel resources in
order to provide that so what you have
to do is even though you're writing a
carbon application or a cocoa
application you need to take some of
these tools top and PS in this case top
if you were looking for leaks right and
just watch your application running and
if you happen to see something leaking
away you need to address that
okay so within a process you actually
you obviously have threads all right and
at the lowest level you have a mock
thread mock does all the scheduling in
the system some mock threads are the
primary threading resource in the system
one really interesting thing about mock
threads it confuses a lot of people is
that they actually have no resources
other than scheduling attributes
attributes and a register state that's
it that is what a mock thread is right
everything else you think about a thread
stacks and per thread data and things
like that
mock doesn't know anything about those
right it's all expected to be wrapped by
some higher-level service and again at
the mock level and an interesting thing
is you can actually you know register
for exception handling and death
notification at the thread level and
those kind of api's still are usable
even when you look
got it in the context of a BST threat or
a pthread POSIX threads are the thing
that provides the resources at the user
level for a threat they provide the
stack for a thread
they provide the thread specific data
implementation all right and those are
the api's you can use to create them and
manage them alright but again you may or
may not just be stopping at a bsd
process right you may be writing a
carbon or a cocoa application and in
those cases right you tend to not write
to P threads you're gonna write to
create a ns thread inside of cocoa or
you're gonna create an MP task in a
carbon application well those are BSD
they are P threads right each and every
one of those is a P thread each one of
each and every one of those is a mock
thread right and so you can have the
breadth of services available to from
each of those layers again at the thread
level if you tried to destroy a mock
thread right out from underneath of a P
thread you can do it your applications
free to do that it can do that to its
own threads you're going to leave the P
thread code implementation and alert
right and so you better not do that but
you could write and one nice thing about
P threads the way the higher-level
application services threading services
wrap around the P thread level is that
almost everything you can do to a P
thread you can do from those on those
higher level services and they tend to
work well with each other
right and so well how do I view threads
in my system how do I tune for it how do
I take care of the threading in my
system and here's some tools you can do
a thread viewer if anyone was at the
performance tools meeting session
yesterday you saw them going and
actually showing thread viewer as an
application that they were debugging
during that process well they at the end
of that meeting they the end of that
session they decided that they were
going to release that thread viewer to
people as soon as possible so that's
going to be a really nice application
for viewing threads in the system in a
graphical way and
higher level because up until that point
well you could sample threads with the
sample app but that's kind of not
something you would do ongoing and just
watch your application go it's typically
you've noticed a problem right and you
would fire up sampler and go up and do
what you needed to do right and top and
PS I know I've had top running on the
side of my system forever right but it's
it's a lot it's like drinking from a
firehose that's a lot of information it
doesn't give you a graphical bang
there's something going on there that I
really need to worry about some of the
tips well in Mac OS 10
we promote people to lazy in it as much
as possible in their system right if you
have a framework or anything else in
your system you really want to delay
initializing it one of the problems with
the big bounces the bounce marks when
you're launching an application intent
is that a lot of the code brought over
from nine basically had this model
initialize everything once upfront right
as much as you can and then will use it
later right almost for free well in 10
what you're doing is initializing it all
up what upfront once each time each
application launches right and so one of
the services you can use to get around
that problem is this pthread ones
facility which basically at the front of
each major access point into your
service right you can put a P thread
once call the initialization routine at
the front of that right and the P
threads code will guarantee that the
very first time you call one of your
functions that has this in it it'll go
call the initialization routine but it
won't ever allow it to be called again
from that code so that way you can delay
your initialization until the very first
time you're called now also a lot of
people like to create their own
debuggers or their own debugging
environment and so they tend to want to
get the exceptions from an application
as it's running filter them through
their own set of interfaces right and
decide whether or not to let the system
see
rest of them later and so you can catch
exceptions at any one of three places in
mock right you can catch exceptions at
the thread level at the tasks level and
you can actually catch them at the the
widest level the host level all right
BSD tends to hook itself at the host
level and so you know when a processor
thread runs along and executes invalid
instruction it's gone is send an
exception down this chain it's gonna
first send the exception message out to
the thread level handler the thread
lilifer thread level handler says he
handled it then fine we'll just let the
thread continue and we'll we'll go on
from there if he didn't then you were
gonna send it on to the next level right
to the process level the task level and
there's another handler sitting there if
there is one then we'll send it to him
and then same thing down below
well BSD tends to be at the task level
you're gonna see debuggers like gdb and
things like that are gonna be sitting at
the task level so bsts at the host gdb
is at the task right and if you want to
be able to intercept and get in there
and do something on your own then you
would tend to do it at the thread level
okay so now that we have threads we
obviously have to schedule them right
and how do we schedule them well this
has been somewhat of a mystery inside of
Mac os10 there's obviously something
going on with this banding you can see
different threads being assigned
different priorities but we have we've
been messing with this tuning it and so
we've been kind of adverse to putting
out exactly what the banding is that we
have in the system but now that you're
trying to write real applications right
you're gonna need to know alright some
of you are writing multimedia
applications and you really need to know
how to get to be a fixed priority
process how to how to set your priority
well these are actually the bands that
we have at the very highest so we have a
range from 0 to 127 the very highest
level are what we call time constraint
threads right and so any thread that's
registered as a time constraint thread
and you don't have to be privileged to
say you
you want a time constraint thread right
they will run up in that highest band
somewhere and we that we won't tell you
right but it's based on the time
constraints that you provide and then we
marry that with a bunch of other
information and decide what priority you
actually get within that band right but
they tend to run at a fixed priority in
that band so they'll just run run run
run run run run if they have things to
do and instance there are much higher
band than most other applications
obviously we're going to schedule those
first we're also going to preemptively
schedule those and so even if something
else lowers running along in the kernel
doing your kernel service if one of
these comes along we're going to
schedule it right well that leads into a
concern obviously is that if any
application can do this and can set one
of these threads up really high then
obviously any application can kill the
system and there's no way you'd get it
back it just runs up there forever and
ever
well we actually have limits to what can
happen in a time constraint thread and
so if you're running for too long in a
time constraint thread then you get
bumped back into the normal application
band for a while and then if you settle
down then we'll put you back into the
time constraint band if you don't ever
settle down then you just stay down
there in the in the normal application
ban okay
and actually when you're in the
application in the time constraint bin
you're actually scheduled above the
kernel threads above i/o threads so your
your stuff will happen before will
handle disk activity right it will be
the first thing that kernel will go and
run and then below the kernel in IO is
is the core services threads things like
the the GUI managers right so if you're
running a time constraint thread and
it's just chewing away guess what you
know you you might even have trouble
moving that Mouse around you might have
trouble selecting that application to
kill it right if it runs away that's why
if it's run away it will get bumped down
so that the core service threads have a
chance to run and go ahead and get you
for the rest of the threads you tend
they tend to be grouped into two
categories its GUI based threads and
regular kind of background activity
regular BSD process kind of threads
right and the GUI ones tend to be a
little bit higher in the bands then the
the default ones but all of these
threads are priority adjusted so as they
run and take time they tend to start at
their base and work their way down as
they consume CPU under contention so if
they're consuming CPU and nobody else is
contending for the CPU they're fine
they'll just stay stay stay stay stay as
soon as they start contending for the
CPU with other threads and other things
once around they get nicked a little bit
each time this happens right until those
other threads get a chance to run right
and then as a few Quantum's expire and
they've been nicked then they drift back
up and drift down so every thread tends
to balance itself in this group and
that's the standard policy in the system
is to time share and adjust one of the
things you can do in that category is
assign precedence to your threads so if
I have two priority two normal
application threads right but I always
want this one to have precedence over
this one within my application then you
can use the precedence policy setting
this is given ordering to those and like
I said we have we can take those threads
and schedule them fully preemptively
both kernel end user so we have a fully
pre-emptive kernel if you're a time
constraint thread you will interrupt
things that right out of the kernel and
we'll switch to you immediately right
and we can obviously balance those
across multiple CPUs all right when
you're at the bsd process level well you
have a few more things that come out for
you you have the ability to set nice and
if you've noticed in Mac OS 10 that
actually doesn't do anything but the
later versions that soon you will see a
version that has that fixed right at the
P thread level you can set your own
scheduling attributes all right those
will feed into the precedents
into the timeshare in Lincoln and
standard policy constraints and outlet
the higher-level right you have
management going on even beyond what
this the mock level manages so if you're
writing cooperative threads where you
have deferred threads inside of your
carbon application carbon is actually
getting involved there and trying to
make sure that those things run even
though they're each a mock thread he's
trying to make sure they run in the
right order again you know some of the
standard tools to look at things but the
big tip here is don't use the old api's
for setting things as round-robin or
time share that are still available in
the mach kernel you have use the new get
policy set policy ap is that take the
precedence and the time constraint all
right so now that we've got scheduling
and able to run let's see what we can do
with anything outside of ourselves right
and for that we need to access files
typically right inside of the file
management system of the whole kernel
mock tasks actually has no concept of
file right so you would think that mock
is really not involved in this
discussion but that's not true
every file in the system really is
managed and controlled the cache for the
data that that application is managed
and controlled by mock through what's
called vm objects so mock manages the
cache in the system the vm page cache
and all of our filesystem activity right
goes through the vm page cache to do
what it needs to do so as you're reading
from files reading files off a desk
those files are stored in the regular vm
cache right we don't have a file system
cache and a vm cache for things that are
you know applications that are mapped
into your program we have one cache read
read read read read it all goes into one
pile right and it pushes things off the
end of the pile
right and again at the higher level
those are wrapped yet again by different
handles out at the application level one
interesting that happens the interesting
thing that happens there is that bsd is
this basically a synchronous file access
system right and a lot of the carbon
applications are using a synchronous
file i/o well how that works is that the
actual carbon library in the system will
go ahead and create worker threads that
will issue the synchronous bsd calls for
you right and manage sending you the
asynchronous response later on so if you
open files asynchronously in carbon
right and you start at you start doing
asynchronous reads in carbon or
asynchronous writes don't be surprised
when you go look you know with the tools
and see there's another thread in my
application that I have no can I didn't
create right and it's created for you by
that higher level right some really good
tools to tune your use of files right is
FS usage it's a tool that will basically
as you're accessing a file it will spew
out what's going on every access every
read/write open/close either by a
particular application or by any
application overall and so you can get a
basically a real-time view of everything
that's going on file activity wise also
there's another tool LSO F another
command-line tool both of these are
command line and it'll basically list
every open file in the system right and
who has it open what file descriptor
number it is within that process it's a
very useful tool alright big tip because
we have this one cache right that
handles all mapped files all your
libraries all your frameworks all your
executables and it's also the cache
where you handle you know all the
reading of files reading and writing a
files if you happen to be reading
something once and only once right
spewing in a big image file or something
like that that you're gonna process once
right you don't need that file in the
cache anymore you've got it in your
application right having a copy of it in
your application and having the original
one in the cache
just means we are taking up double the
space in BM at least temporarily for
that data so whenever you can use the no
cash options right at the carbon level
you have no cash reads and writes at the
bsd level we actually have enough
control that you can specify to say
these are no cash operations ya really
need to use the no cash operations
alright otherwise as you run through
memory write with big files you can push
really important pieces of the system
like the system framework and everything
that you use and your own code right out
of memory one thing that also gets
people every once in a while is that
while you typically were able to open in
a carbon application as many files as
you wanted until you hit the system
limit in bsd there's a soft limit for
the number of open per process and
that's 256 right and so as you open ffs
wraps inside of Carbon applications
right you may end up running into this
limit typically it's a bug right
typically it's because you forget them
to close them right and you just open
open open open or open and eventually
you'll hit the 256 limit we basically
you have that limit now you can change
it with a assist control or sorry yeah
there's an API at the bsd level to
basically up the limit for you right the
same thing can happen at a system-wide
level we have a system-wide level of
number of V nodes which are the open
file descriptors up there the open file
handles right and those are you know
there's a system-wide limit determined
that boot time based on the amount of
memory in the system and essentially you
know some other tunable parameters well
you can tune those up as well with us as
control okay now we have files when we
talked a little bit about VM right but
we need to talk about the rest of what
happens with VM right the mach vm pretty
much controls the virtual memory in all
of Mac OS 10 BSD provides some wrapper
services to that but it's mostly managed
by mock right mock provides the
protected address spaces that Mac os10
you know is promoted here we have
protected address spaces right one nice
thing about the way mock does it is you
have basically extreme flexibility and
how you want to assemble an address
space right you can put stuff here there
everywhere it's really wonderful when
you're trying to emulate an old system
well guess what that's exactly what
we're trying to do it's one of the key
benefits of using mock VM is if you
don't put if stuff had to be up there
you can put it up there okay it also
provides control sharing of resources so
you can map things in exclusively into
one application you can map them in
copy-on-write into one but read right
into the other so you can write into
your piece of memory and the other guy
can see it I can't modify it right or
you can map things in readwrite into
both all right so it's a really flexible
way of putting systems together right
and what does it look like well we
showed in the picture before we showed a
VM object and we showed cache pages
sitting off of it and we showed this
thing called a V node well the V node
from the mock view of things is just an
abstract memory manager it doesn't
understand what that is all right it
just has a protocol to talk to it and
anybody can be one of those right and
provide services and as long as you do
will do the right thing well here you
have to address faces each one of which
has some portion of an object mapped in
in this case they tend to have they have
the same object mapped in the same part
of the same object but they haven't
mapped at two different addresses ones
up at zero and the other ones somewhere
down inside right and so you're running
along and all of a sudden one of the
guys takes a fault because the page
isn't existing all right so we send a
message basically not send a message but
the the address space queries the
virtual memory object and says do I have
this page cache well guess what no I
don't have this page cache so let me put
a placeholder in case somebody else
comes along and tries to do the same
thing I won't do this again right which
is sending a request to the memory
object and the memory object sends back
a data page and then we make that data
page available in the application
it's an L of a sudden you can go on and
run but look what happened over in the
other address space the guy with the
same area mapped in but in a different
part of his address space well we have
the page cache now he doesn't have the
page available to him right and if you
had 250 objects that these guys share in
common each one would have to have 250
entries pointing at you know each of the
individual objects well if you're
absolutely sure that you're going to
have a whole bunch of them objects that
are in common between two applications
you can set up what's called a shared
region which basically is a recursive
address space right you can have an
address space entry that points at
another address space for any portion of
it all right and we tend to use this in
our system and I'll show you what for in
a second right but we have two of them
that we put into place one that tends to
be sitting it's seven bazillion and the
other one that's sitting at a bazillion
right one is directly mapped shared by
each of the applications and another is
mapped copy-on-write by each of the
applications so let's get rid of that
copy-on-write one because it's a little
confusing right for the moment right and
what's backing that that shared address
space well the same stuff that was
backing the other address space right a
reference to a memory object which has
some cache pages associated with it and
a reference off to some manager that
knows how to fill in the data that it
doesn't already have cached so now you
come along and take a fault on that
address right it queries the the shared
address space and the shared address
space then doesn't have the page either
so it basic query is the object itself
and we gotten up we don't have it so
let's put a placeholder in place and we
put the placeholder in the shared region
well guess what because it's truly
shared by the other guys the placeholder
actually shows up in everybody at the
same time right we sent the request on
to the pager when he sends the data back
wham the data shows up in every address
space at the same time what do we use
that for well
if you take a dump of a typical mop Co
application this is the layout you're
gonna see right down it zero we tend to
have a guard page all right that'll
catch zero faults you know zero
references and raise an exception for
you if you don't like that idea you can
go ahead and put another page there it's
fine just replace that but that's the
typical behavior right starting on the
first page on up to the first gigabyte
is typically your application where the
application itself is mapped where the
heaps and stuff tend to come right but
heaps can be there and they can be you
can fill up basically any of the space
any of the holes in here with memory
that you like so if you have a heat
manager and like ours the basis says get
me hunks right and then I'll subdivide
them right once you run out of space
between the application and one gig if
you have more than that in heaps it'll
go and find spots basically the first
fit for another chunk going on up the
line but if you notice it's seven and
eight bazillion respectively right
there's a read-only section and a
copy-on-write section well this is where
all the frameworks tend to fall right
that your applications use so we have 70
some-odd frameworks that are a standard
part of Mac OS 10 right if we had to map
those into each application separately
right and manage them separately and
relocate them separately right we'd be
going through a lot of extra overhead
right as each application launched so
what we do instead is have a shared
region that points off at all the shared
text of an application we relocate it
once if it has to be relocated but
typically it doesn't because a lot of
our system is pre bound our libraries
and they sit and point off in that one
area right and then we map the data part
of that you know add another one or yeah
256 Meg off of that right copy-on-write
into each application so as each one
takes a rights particular parts of the
data they get their own copy by doing
this
at 256 Meg offsets we actually get to
take advantage of something that happens
in the powerpc right which is that you
can actually truly share TLB entries and
everything like that on a 256 Meg
boundary with people so at the 7
bazillion where all the frameworks are
alright we're actually sharing TLB
entries and everything between every
application right unless that
application goes in and replaces the
library or overloads the library or says
you know use a different library for me
right then we have to relocate the other
parts of that collection of libraries at
which point you get your own private
copy and it behaves like a traditional
old-fashioned application right so how
do you go ahead and debug a you know the
VM services you have well one of the
best benefi will to you if you are
watching at the tool session yesterday
is malloc debug it's a wonderful thing
to see you know individual parts of your
heap being leaked leaked away and
whether or not you're actually using
them anymore and whether they could be
reclaimed right but that doesn't catch
memory allocations that happen outside
of the heap manager right and there's
lots of reasons why memory would be
allocated outside the heap manager and
directly fill up your address space
right and there's this tool called VM
map which will actually just give you a
dump of all the it's a command-line tool
sorry that will give you a dump of all
the mappings in your system in your
application and you can find the ones
that you don't seem to realize you don't
remember having right and start
investigating those and what you'll tend
to find is that something sent you a
piece of memory and you just forgot
about it all right something in the
system sent it to you out of line in a
message or some other way or you
allocated a hunk directly with VM
allocate right instead of using the the
malloc tools and you just let it dangle
all right and that will show you those
you can also see those in top right so
you the police you go first is top and
to watch your application running if you
see the number of memory entries going
up and up and up and up and up right
you're probably forgetting to do
it's something that you really needed to
deallocate all right one of the things
that happens is when you do one of those
VM allocates right they tend to start at
zero and find the first fit right so
when you're looking through your address
map and you see a bunch of entries up by
zero right these are probably pieces of
memory that were allocated with the
Amalekite and you might want to look at
those another really important tip goes
along with the no cash option is if you
map things into your address space or
you malloc a big hunk of memory right or
you allocate it and you use it and now
you're done with it but you know you
really don't want to keep allocating it
and deallocating it because maybe it's
expensive well you want to kill it all
right kill it out of the cache and
there's a couple of ways you can do that
there's an EM sync option at the POSIX
level that let you kill pages there's
another one at the Mach level called vmm
sync they're really useable
interchangeably depends on what API set
you want to stick to but you need to
kill them okay so we talked about all
these things we've got you know tasks
and threads and address spaces and
they're all protected but when you have
a protected address space in a protected
environment you need to communicate
somehow and so that brings us to the IPC
services right and again Mach plays a
big part in the IPC services of Mac OS
10 not so much in what happens at the
BSD level so in a BSD process it might
not be that important but in Mac OS 10
in general it actually becomes very
important so an address sorry the basic
idea of IPC service in Mac OS 10 is mock
IPC mock IPC manages writes in port
namespaces associated with each task you
have rights to ports it's kind of like
an open file descriptor inside of BSD
but instead it's - a communications
channel a small one called a mock port
so here I have a mach port in the second
task that gives me the right to send the
message to the first task what's really
nice about Mac o
ten or about Mach IPC is that if you
have memory and you have other port
rights right you can collect those
together and send them in messages over
to the other task and so you can do
really flexible communication so I've
got a piece of memory in my address
space in task 2 and I've got another
port right in task 2 one that I own the
receive write for and what I do is I
build a little message that basically
contains you know some general
description of what I'm sending but it
also contains a reference to each of
these things right and I send it over to
the test to that port that I have right
and when it's received over in task one
guess what now he has new virtual memory
and he has new port rights right and so
he can use the port right I just get
gave him to send the message back to me
saying I'm done what I'm doing all right
and so all the RPC in the interaction
that goes on inside of Mac OS 10 or a
large portion of it happens via this
mechanism when you want to open a window
write that in a GUI application well the
frameworks inside of your application
talked to the core graphic server the
window server by sending a message a
mock message over there saying we need
to do something and what they do is they
arrange to have a piece of shared memory
in common to do most of the
communication but then they are
constantly sending messages back and
forth to each other about what the state
of that is so again you have this inside
of each task you have a collection of
these ports right and they can represent
you know just a basic message queue
there's also variants there like
semaphores lock sets right there handles
to things that the kernel implements and
they can be collected in sets and that
collection in sets is really important
because if you look inside of an
application that GUI application in Mac
OS 10
you gotta see at least one of these CF
run loop things right which is the basic
primitive of the event mechanism inside
of Mac OS 10 and a CF run loop is
actually just a wrapper around a mock
port set right or a collection of mach
port set so you may have many port sets
and the CF run loops own some of them
and put some rights and portraits into
them and each of those port rights
represents
thing that can drive events a source of
events that your application may need to
deal with so he's already got a bunch in
this support set but you know as time
goes on he has more and more and more
and what what you realize is while
you're talking to a lot of things inside
of Mac os10 V ports every once in a
while you're talking to her traditional
BSD application or you're talking to a
traditional you know who knows right
there's lots of other ways you can
communicate with things but you need to
somehow you know most applications feed
that back into the run loop so that your
application can see the events driven by
these other sources well you can't be
sitting at a single weight right when
you do a CF run loop wait all right
it sits on a port set waiting for a
message right if that isn't coming in
via port set that thread isn't going to
see it or through a port it's not gonna
see it so that thread connect that run
loop can actually create worker threads
for the kinds of IPC that he doesn't
that is in port based receives the in
this case off of a socket receives the
message off a socket or the data office
socket and tickles another port inside
the port set to wake the run loop up
some of those other sources that you can
get things on right at the bsd level you
have sockets and POSIX semaphores right
and you have P thread synchronizers
right now the P thread synchronizers our
intro task only but as time goes on
they'll become you know inter task as
POSIX says they're allowed to be and
then they're gonna have to feed into
this mechanism as well if you want to be
able to receive them in a single place
right and then what happens at the outer
level again is you have a port set
that's wrapped by a run loop that
becomes the foundation of your event
queue inside of your application and so
well as you're watching your
applications your main thread is going
to be calling you know wait next event
let's hopefully not maybe it's you
hopefully it's using carbon events but
if it is calling wait next event that's
going to be calling CF run loop
we'll see if run loop actually built up
one of these port sets of all the things
that can drive events into it right and
then that's calling Mach message trap
typically Mach message overwrite trap
doing a receive waiting for stuff to
come in right so you're gonna see that
over and over and over and over again in
each of your applications again when
you're looking in sampler you're gonna
see that kind of thing you're also gonna
see it in SE usage and you're gonna if
you run se usage at the bottom it tends
to list all the threads and what they're
doing what they're currently waiting on
all right and you're gonna see Mach
message over I trap Mach message over I
trap mic message overwrite trap message
over a trap right they're all coming in
on run loops of some sort or another or
directly receiving on a Mach message
right ports represent almost everything
in my core or in Mac os10
a large portion of things so like again
if you have a window open the handle for
the window is a port so when you look at
the cg debug stuff phrase has a list
down the side of the things the ports
that it has open to represent each one
of those windows right and if you're
tempted to use the the IPC directly the
mock IPC we prefer you not there's a
tool called mig it's mock interface
generator and it's basically an ideal
compiler that wraps around mock
messaging and you can specify routines
that go both directions or one-way
messages and it generates wrapper
routines that generate those messages
for you and receive those messages for
you so you don't have to understand and
manipulate the low-level messaging it's
just a nice convenience okay so now we
have the ability to communicate but
we're supposed to have a secure system
here all right how do we do that well
again a lot comes back to those ports
you have ports are restricted you can't
just invent a port name inside of mock
and say I want to send a message to that
port right you have to somebody has to
give you that
or ascend right to that port in the
first place now some of them are
registered globally we can just look
them up and get them so you can send
some common service a message saying I
want to do something and it'll respond
to that all right but in a lot of ways a
lot of cases they aren't registered
globally so maybe you'll talk to a
service through a global port and it
will send you back a port that only you
can talk to it to directly manipulate
your windows that's why inside of the
Windows Server communication right you
get a new port per window because it
only wants you and only you to be able
to manipulate that window and the port
right mechanism allows that to happen
without him doing anything on his side I
received a message on that port it must
be him or somebody he delegated to send
this message I'll do it right so they're
pre-authorized and in fact Mac OS I mean
MOC part of Mac OS 10 has no
authorization facility at all right it
basically says if you've got that port
and you send a message on it we'll do
what that message says to do right and
those messages those ports represent
things inside of the kernel as well so
if you have a task or a thread or any of
those other kernel resources they're
represented by unique ports you get a
hold of one of those ports a thread port
you send a message to it saying
terminate guess what it'll terminate
right so you got to be careful about
sending your ports out but it's also a
really nice mechanism to say you know
we're not going to just say that ap eyes
are available and usable by the
application themselves like threading ap
eyes if that application wants to send
its thread port over to a friend that
friend can issue all the threading api's
itself directly on that port and we'll
treat it at the kernel level just like
the application had done it itself the
same thing with managing the port space
the port space is represented by the
task port and so getting things in and
out of your own port space is done with
that same thing the only nod to
authorization that the the Mach level
services provide is that each message
that sent is sent with a tag some
kind of security tag on it that
basically says I don't know what this is
but somebody said five was associated
with the guy who sent this message so
I'm gonna send five along right well
what happens is the BSD layer is the guy
who says what five means right he
provides the identification and
authorization in the system
identification is you IDs inside the BSD
world right user IDs you have user IDs
and effective user IDs and your group
IDs an effective group IDs and you have
you know correct collection of groups
that you're allowed to be in right and
whatever you BSD says this task has a
security token is what gets sent along
well BSD is also the guy who maintains
permissions at the file level makes
sense because he's the guy who
implements the file systems at his level
and so all the authorization to gain
access to files is done by the BSD layer
right and he does somewhat similar to
what MOC does right once he gains has
given access to something through the
file system he has a file descriptor
which is basically the access point the
restricted access point and permissions
are associated with that file descriptor
so it's it's pre-authorized pre cached
authorizations right but BSD semantics
and pot and mock semantics alone aren't
enough for Mac os10 in general right you
have applications that want to run as a
general user a regular old user that
need to do privileged things right
sometimes we have a privilege server
that's just sitting over there waiting
to do that thing for you right and other
times we have a server that is
privileged to do specific things and
will authorize you time each time to to
do that one particular thing through the
new authorization API that happens as a
core service API right also at that
level you have keychains and key chain
management and all that stuff is done up
above the basic primitives of the BSD
file and UID stuff and the MA
sport stuff all right
again FS usage is nice because it shows
you what kind of accesses you're doing
to a file LS Oh F will tell you what
kind of access is you have to a file VM
map will tell you what kind of
permissions you have on certain memory
so if you've read write or rewrite
copy-on-write so that when you actually
touch the thing you get a unique copy
instead of being able to write to the
actual main store so you can get a feel
for what's going on in the system that
way
one thing to do is take a nod from the
Mach part and the BSD part which is to
cash authorizations right if you have to
do some of your own work well yes you
could set up a server that receives
messages and just constantly looks at
the the security token on the bottom of
a message and says well am I allowed to
take this from this guy because he says
he's five right do I allow five to do
this or do I say no right that's kind of
awkward to keep doing that over and over
and over again right so you would prefer
to establish a unique connection with
each of your clients in that situation
and receive only and pass out the send
right on the other side only to that one
guy and then every time a message comes
in on that right you allow him to go
ahead and access it all right so those
were the basic services inside the
kernel right where can you get more
information about how this stuff all
really works because this was far too
much and far too quick to get to much of
anything totally useful out of it well
there's a good resource right on the
developer CD and if you've installed
that now it's right on the disk of your
system and most people don't even
realize it's there right under the
developer section there's a
documentation section under that there's
a kernel section right and there's
descriptions there's a basic description
of the kernel services again some more
details about how they're managed what
the api's are and especially on this
particular part there's a reference to
something called the OSF documentation
well our mock kernel is the OSF mach
kernel
so if you clink click through that link
you're going to go ahead and find the
documentation for the mocks api's that
we have in our system they're not 100%
accurate they're quite a few years old
and we've made some changes internally
but they're pretty good and it gives you
a really good idea of how the mock part
of the system works there's obviously
the Darwin open source pages you can go
to those all right and the Mac os10 home
page and our tech writers have renamed
the book on me it's the design
implementation of the four for BSD
operating system by mcusic it's great
for the BSD side of things right where
can you learn more here today sorry but
for those of people who are watching via
the DVD later on you can go look up
these sessions the performance tool
session was really good it shows you how
to see the effects of all of these
interactions inside of an application
that you're writing the same thing with
the debugging stuff so when you get your
CD later go look at the debugging and
the performance stuff they're really
important you just saw the leveraging
the BSD more than likely if you were
here and in a few minutes you'll get to
do feedback
[Applause]
you