<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://www.foldr.org/~michaelw/log/theme/style/rss.css" type="text/css"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xml:lang="en">

	<channel>
		<title>Random Bits and Pieces :: computers/macosx</title>
		<link>http://www.foldr.org/~michaelw/log</link>
		<description>Michael Weber</description>
		<language>en</language>
		<lastBuildDate>Sat, 15 Aug 2009 19:43:00 GMT</lastBuildDate>
		<generator>blosxom ver.2.0</generator>


		<item>
			<title>Tooth Pain</title>
			<link>http://www.foldr.org/~michaelw/log/computers/macosx/bluetooth-pain-10-5-8</link>
			<guid isPermaLink="true">http://www.foldr.org/~michaelw/log/computers/macosx/bluetooth-pain-10-5-8</guid>
			<category>http://www.foldr.org/~michaelw/log/computers/macosx/</category>
			<pubDate>Sat, 15 Aug 2009 19:43:00 GMT</pubDate>
			<content:encoded><![CDATA[
<img src="http://www.foldr.org/~michaelw/log/static/computers/macosx/bluetooth-icon.png" alt="Bluetooth Icon" />

<p>I cannot recommend the MacOS X 10.5.8 upgrade.  It promised to
  improve Bluetooth connectivity (my mouse occasionally loses
  connection shortly).  After the upgrade, I now have to reboot to
  access <abbr title="Bluetooth">BT</abbr> keyboard and mouse after
  waking up the MacBook from sleep.
</p>

<p>This seriously sucks.  Dear Internet, if you happen to know a way
  around this please
  do <a href="mailto:michaelw+comments@foldr.org">help me out</a>.</p>

<img src="http://www.foldr.org/~michaelw/log/static/computers/macosx/bluetooth-pain.png" 
     alt="Screenshot of non-working OS X Bluetooth"
     class="center" />
]]></content:encoded>
			<comments>http://www.foldr.org/~michaelw/log/computers/macosx/bluetooth-pain-10-5-8#writeback</comments>
		</item>

		<item>
			<title>Click-Click</title>
			<link>http://www.foldr.org/~michaelw/log/computers/macosx/click-click-time-machine</link>
			<guid isPermaLink="true">http://www.foldr.org/~michaelw/log/computers/macosx/click-click-time-machine</guid>
			<category>http://www.foldr.org/~michaelw/log/computers/macosx/</category>
			<pubDate>Mon, 27 Jul 2009 11:47:00 GMT</pubDate>
			<content:encoded><![CDATA[
<img src="http://www.foldr.org/~michaelw/log/static/computers/macosx/time-machine-icon.png" alt="Time Machine Icon" />

<cite>
<q>Click-click</q><br/>
<q>Click-click who?</q> <br/>
<q>Click-click, dead hard disk, harbinger of panic attacks.</q>
</cite>

<p>Thankfully, I am
  somewhat <a href="http://www.foldr.org/~michaelw/log/events/offsite-backups">battle-hardened</a> in
  this regard, and I had been using
  Apple's <a href="http://www.apple.com/macosx/what-is-macosx/time-machine.html">Time
  Machine</a> as backup strategy.  Even more lucky, I recently bought
  a <abbr title="Network Attached Storage">NAS</abbr> solution which
  automates backups completely and allowed me to forget about
  them.</p>

<p>The only remaining thrill was that until now, I did not get around
  verifying that a full restore actually works.  However,
<a href="http://blog.duncandavidson.com/2008/01/restoring-from-time-machine.html">Restoring
  from Time Machine</a> delivers as advertised.  A couple of hours
  after exchanging the hard disk, everything was back up again.
</p>

<p>There are two small snags I encountered, though.  First, the MacOS X
  installer does not recognize a completely empty hard disk.  I used
  the <q>Disk Utilities</q> application (from the <q>Utilities</q>
  menu) to format the hard disk.</p>

<p>Second, while this is good enough for the installer to work, the
  <q>Restore</q> application still does not see the (now-formatted)
  hard disk.  It helped to go back to the initial dialog of the
  installer (in which the language can be selected) and then go forward
  until I could choose <q>Restore System from Backup</q> (again from
  the <q>Utilities</q> menu).</p>
]]></content:encoded>
			<comments>http://www.foldr.org/~michaelw/log/computers/macosx/click-click-time-machine#writeback</comments>
		</item>

		<item>
			<title>Build Yourself 64-Bit MacPorts in Under Five Minutes!</title>
			<link>http://www.foldr.org/~michaelw/log/computers/macosx/64-bit-macports</link>
			<guid isPermaLink="true">http://www.foldr.org/~michaelw/log/computers/macosx/64-bit-macports</guid>
			<category>http://www.foldr.org/~michaelw/log/computers/macosx/</category>
			<pubDate>Mon, 15 Jun 2009 11:43:00 GMT</pubDate>
			<content:encoded><![CDATA[
<img src="http://www.foldr.org/~michaelw/log/static/computers/macosx/finder-icon.png" alt="Finder Icon" />

<p>
Despite my earlier
voiced <a href="http://www.foldr.org/~michaelw/log/computers/macosx/macports-fatally-flawed">contempt
for MacPorts</a>, I present you
<a href="http://www.foldr.org/~michaelw/log/static/computers/macosx/build_macports64">build_macports64</a>,
a small script which bootstraps a
64-bit <a href="http://www.macports.org/">MacPorts</a> environment
from their SVN repository.  No manual intervention is required.
</p>

<p>Dependencies: 32-bit MacPorts installed (you want to keep it anyway
for the moment), and a configured
<a href="http://en.wikipedia.org/wiki/Sudo">sudo</a>.  By default, it
installs to <tt>/opt/local64/</tt>.
</p>

<p>I have the following packages build and installed
  (here, <tt>universal</tt> means <tt>x86_64</tt>):</p>

<pre>
% <kdb>port installed</kdb>
The following ports are currently installed:
  apr @1.3.3_1+universal (active)
  apr-util @1.3.4_1+universal (active)
  bzip2 @1.0.5_2+universal (active)
  curl @7.19.5_0+universal (active)
  db45 @4.5.20_4+universal (active)
  db46 @4.6.21_5+universal (active)
  expat @2.0.1_0+universal (active)
  gettext @0.17_4+universal (active)
  gmake @3.81_0+universal (active)
  gperf @3.0.4_0+universal (active)
  libiconv @1.12_2+universal (active)
  ncurses @5.7_0+universal (active)
  ncursesw @5.7_0+universal (active)
  openssl @0.9.8k_0+universal (active)
  pkgconfig @0.23_1+universal (active)
  popt @1.15_0+universal (active)
  readline @6.0.000_1+universal (active)
  sqlite3 @3.6.14.1_0+universal (active)
  tcl @8.5.6_0+threads+universal (active)
  zlib @1.2.3_2+universal (active)
</pre>

<p>Sadly, at the moment there are some crucial packages which do not
  build as x86_64 even if requested (perl, boost).  For others,
  the build just breaks, e.g., because <code>CFLAGS</code> are
  not passed properly.  But that was to be expected, I guess.  With
  more people using it and reporting/fixing bugs, the situation is
  likely to improve over time.
</p>
]]></content:encoded>
			<comments>http://www.foldr.org/~michaelw/log/computers/macosx/64-bit-macports#writeback</comments>
		</item>

		<item>
			<title>Some Fun with Mach Ports</title>
			<link>http://www.foldr.org/~michaelw/log/computers/macosx/task-info-fun-with-mach</link>
			<guid isPermaLink="true">http://www.foldr.org/~michaelw/log/computers/macosx/task-info-fun-with-mach</guid>
			<category>http://www.foldr.org/~michaelw/log/computers/macosx/</category>
			<pubDate>Fri, 13 Mar 2009 20:09:00 GMT</pubDate>
			<content:encoded><![CDATA[
<img src="http://www.foldr.org/~michaelw/log/static/computers/macosx/hexley.gif" alt="Hexley, the mascot for OSX/Darwin" />
<p>
Suppose we want to monitor memory and time usage of a child process.
Frequently.  On MacOS&nbsp;X.  With an unprivileged user.  I did not find
anywhere a description of how to achieve this.  This articles pulls
together some of the needed information.
</p>
<p>
MacOS&nbsp;X's <a href="http://developer.apple.com/documentation/Darwin/Conceptual/KernelProgramming/">Mach
kernel</a> surely does not make it straight-forward, but the biggest
showstopper is the lack of documentation on how the low-level
operations are supposed to be used together.  Apple's stance appears
to be that
they <a href="http://lists.apple.com/archives/Unix-porting/2006/Aug/msg00001.html">do
not like these interfaces to be used</a>.  It was even suggested
to <a href="http://lists.apple.com/archives/unix-porting/2006/Jan/msg00093.html">parse
the output of the <tt>ps</tt> utility</a> which is not such a hot idea
if the monitoring has to be done frequently enough.  Adequate
high-level interfaces are not provided either.
</p>

<h3>The Big Picture</h3>
<p><em>Note: much of the following was learned by reading random
    (undocumented) source code and guess work.  Please let me know
    about any inaccuracies.</em>
</p>
<p>
Not very long ago, <a href="http://kuriositaet.de/">Tim Becker</a>
wrote an article
on <q><a href="http://blog.kuriositaet.de/?p=257">Determining memory
usage in process on OSX</a></q>.  The function to use
is <code><a href="http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/task_info.html">task_info</a>()</code>,
which takes a <em>task port</em> as parameter.  We can obtain a task
port for our own process
via <code><a href="http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_task_self.html">mach_task_self</a>()</code>.
For arbitrary processes, the first function that comes to mind
is <code>task_for_pid()</code>, which, given a <code>pid_t</code>,
returns its task port.  But, since we can do a lot of nasty things
with task ports, it is a privileged operation, at least on newer
versions of OS&nbsp;X (for Intel Macs).
</p>
<p>
So, we need a different way to get at the task port of a process.  In
Mach, we have to ask the other process nicely whether it grants us
this right.  For <code>fork()</code>ed processes, we can establish a
communication channel between parent and child, on which the child
sends its own task port back to the parent.  The parent process is
then free to use it in the call
to <code><a href="http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/task_info.html">task_info</a>()</code>
to obtain information about its child.
</p>

<h3>Fork(1) It!</h3>

<p>There is one small problem, though.  In contrast to, e.g., Unix
  file descriptors, task ports are not inherited across
  a <code>fork()</code>.  Hence the parent process must set up a
  special <em>bootstrap port</em> to get things off the ground.  Since
  the parent is at the receiving end, the port must be created
  with <code>MACH_PORT_RIGHT_RECEIVE</code>.
</p>
<p>
  Furthermore, the parent process must explicitly grant its child the
  right to send back messages via this port.  This is done in
  function <code>setup_recv_port()</code> below.
</p>
<pre class="clang">
<span class="keyword">static</span> <span class="type">int</span>
<span class="function-name">setup_recv_port</span> (<span class="type">mach_port_t</span> *<span class="variable-name">recv_port</span>)
{
    <span class="type">kern_return_t</span>       <span class="variable-name">err</span>;
    <span class="type">mach_port_t</span>         <span class="variable-name">port</span> = MACH_PORT_NULL;
    err = mach_port_allocate (mach_task_self (),
                              MACH_PORT_RIGHT_RECEIVE, &amp;port);
    CHECK_MACH_ERROR (err, <span class="string">"mach_port_allocate failed:"</span>);

    err = mach_port_insert_right (mach_task_self (),
                                  port,
                                  port,
                                  MACH_MSG_TYPE_MAKE_SEND);
    CHECK_MACH_ERROR (err, <span class="string">"mach_port_insert_right failed:"</span>);

    *recv_port = port;
    <span class="keyword">return</span> 0;
}
</pre>

<p>
Subsequently, the newly created port is set as bootstrap port in the
parent.  It is the only port that is inherited by child processes.
</p>

<pre class="clang">
<span class="type">kern_return_t</span>       <span class="variable-name">err</span>;
<span class="type">mach_port_t</span>         <span class="variable-name">parent_recv_port</span> = MACH_PORT_NULL;

<span class="keyword">if</span> (setup_recv_port (&amp;parent_recv_port) != 0)
    <span class="keyword">return</span> -1;
err = task_set_bootstrap_port (mach_task_self (), parent_recv_port);
CHECK_MACH_ERROR (err, <span class="string">"task_set_bootstrap_port failed:"</span>);
</pre>

<p>
For the child process to send a message back to its parent process it
first asks for the bootstrap port.  Then we create a message which
contains the task port we want to send back (the magic constants may
or may not be completely correct, but they appear to work) and send it
(function <code>send_port()</code>):
</p>

<pre class="clang">
<span class="keyword">static</span> <span class="type">int</span>
<span class="function-name">send_port</span> (<span class="type">mach_port_t</span> <span class="variable-name">remote_port</span>, <span class="type">mach_port_t</span> <span class="variable-name">port</span>)
{
    <span class="type">kern_return_t</span>       <span class="variable-name">err</span>;

    <span class="keyword">struct</span> {
        <span class="type">mach_msg_header_t</span>          <span class="variable-name">header</span>;
        <span class="type">mach_msg_body_t</span>            <span class="variable-name">body</span>;
        <span class="type">mach_msg_port_descriptor_t</span> <span class="variable-name">task_port</span>;
    } <span class="variable-name">msg</span>;

    msg.header.msgh_remote_port = remote_port;
    msg.header.msgh_local_port = MACH_PORT_NULL;
    msg.header.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0) |
        MACH_MSGH_BITS_COMPLEX;
    msg.header.msgh_size = <span class="keyword">sizeof</span> msg;

    msg.body.msgh_descriptor_count = 1;
    msg.task_port.name = port;
    msg.task_port.disposition = MACH_MSG_TYPE_COPY_SEND;
    msg.task_port.type = MACH_MSG_PORT_DESCRIPTOR;

    err = mach_msg_send (&amp;msg.header);
    CHECK_MACH_ERROR (err, <span class="string">"mach_msg_send failed:"</span>);

    <span class="keyword">return</span> 0;
}
</pre>

<p>
On the parent side, we prepare to receive the same message (with a
some trailing information tacked on for whatever reason).  And
voil&agrave;, we have the child's task port.  It can later be used
as first parameter to
a <code><a href="http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/task_info.html">task_info</a>()</code>
call.
</p>

<pre class="clang">
<span class="keyword">static</span> <span class="type">int</span>
<span class="function-name">recv_port</span> (<span class="type">mach_port_t</span> <span class="variable-name">recv_port</span>, <span class="type">mach_port_t</span> *<span class="variable-name">port</span>)
{
    <span class="type">kern_return_t</span>       <span class="variable-name">err</span>;
    <span class="keyword">struct</span> {
        <span class="type">mach_msg_header_t</span>          <span class="variable-name">header</span>;
        <span class="type">mach_msg_body_t</span>            <span class="variable-name">body</span>;
        <span class="type">mach_msg_port_descriptor_t</span> <span class="variable-name">task_port</span>;
        <span class="type">mach_msg_trailer_t</span>         <span class="variable-name">trailer</span>;
    } <span class="variable-name">msg</span>;

    err = mach_msg (&amp;msg.header, MACH_RCV_MSG,
                    0, <span class="keyword">sizeof</span> msg, recv_port,
                    MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
    CHECK_MACH_ERROR (err, <span class="string">"mach_msg failed:"</span>);

    *port = msg.task_port.name;
    <span class="keyword">return</span> 0;
}
</pre>

<p>
  The parent process now has access to the child's <code>task</code>.
  Now we need to do some cleanup work.  We need to restore the
  original bootstrap port both in parent and child process.  This is
  so that both have access to the Mach bootstrap daemon again.  This
  can be done by having the child process create another port with the
  above functions, and send it to the parent.  Through this, the
  parent process then sends back its original bootstrap port to the
  child.  (There is probably a simpler way to achieve this.  I would
  gladly like to know.)
</p>

<p>Here's the code:</p>
<pre class="clang">
<span class="keyword">static</span> <span class="type">task_t</span>       <span class="variable-name">child_task</span> = MACH_PORT_NULL;

pid_t
<span class="function-name">sampling_fork</span> ()
{
    <span class="type">kern_return_t</span>       <span class="variable-name">err</span>;
    <span class="type">mach_port_t</span>         <span class="variable-name">parent_recv_port</span> = MACH_PORT_NULL;
    <span class="type">mach_port_t</span>         <span class="variable-name">child_recv_port</span> = MACH_PORT_NULL;

    <span class="keyword">if</span> (setup_recv_port (&amp;parent_recv_port) != 0)
        <span class="keyword">return</span> -1;
    err = task_set_bootstrap_port (mach_task_self (), parent_recv_port);
    CHECK_MACH_ERROR (err, <span class="string">"task_set_bootstrap_port failed:"</span>);

    <span class="type">pid_t</span>               <span class="variable-name">pid</span>;
    <span class="keyword">switch</span> (pid <span class="warning">=</span> fork ()) {
    <span class="keyword">case</span> -1:
        err = mach_port_deallocate (mach_task_self(), parent_recv_port);
        CHECK_MACH_ERROR (err, <span class="string">"mach_port_deallocate failed:"</span>);
        <span class="keyword">return</span> pid;
    <span class="keyword">case</span> 0: <span class="comment-delimiter">/* </span><span class="comment">child </span><span class="comment-delimiter">*/</span>
        err = task_get_bootstrap_port (mach_task_self (), &amp;parent_recv_port);
        CHECK_MACH_ERROR (err, <span class="string">"task_get_bootstrap_port failed:"</span>);
        <span class="keyword">if</span> (setup_recv_port (&amp;child_recv_port) != 0)
            <span class="keyword">return</span> -1;
        <span class="keyword">if</span> (send_port (parent_recv_port, mach_task_self ()) != 0)
            <span class="keyword">return</span> -1;
        <span class="keyword">if</span> (send_port (parent_recv_port, child_recv_port) != 0)
            <span class="keyword">return</span> -1;
        <span class="keyword">if</span> (recv_port (child_recv_port, &amp;bootstrap_port) != 0)
            <span class="keyword">return</span> -1;
        err = task_set_bootstrap_port (mach_task_self (), bootstrap_port);
        CHECK_MACH_ERROR (err, <span class="string">"task_set_bootstrap_port failed:"</span>);
        <span class="keyword">break</span>;
    <span class="keyword">default</span>: <span class="comment-delimiter">/* </span><span class="comment">parent </span><span class="comment-delimiter">*/</span>
        err = task_set_bootstrap_port (mach_task_self (), bootstrap_port);
        CHECK_MACH_ERROR (err, <span class="string">"task_set_bootstrap_port failed:"</span>);
        <span class="keyword">if</span> (recv_port (parent_recv_port, &amp;child_task) != 0)
            <span class="keyword">return</span> -1;
        <span class="keyword">if</span> (recv_port (parent_recv_port, &amp;child_recv_port) != 0)
            <span class="keyword">return</span> -1;
        <span class="keyword">if</span> (send_port (child_recv_port, bootstrap_port) != 0)
            <span class="keyword">return</span> -1;
        err = mach_port_deallocate (mach_task_self(), parent_recv_port);
        CHECK_MACH_ERROR (err, <span class="string">"mach_port_deallocate failed:"</span>);
        <span class="keyword">break</span>;
    }

    <span class="keyword">return</span> pid;
}
</pre>

<p>
Documentation about
the <a href="http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/">Mach
IPC Interface</a> is available.  In principle, I like how port rights
(capabilities) are handled in Mach, compared to the Unix way of
sharing almost everything across a <code>fork()</code>.  If only it
would have been made easier to discover the details.
</p>

<p>(On Linux, all this would have been done by reading the information
  we are interested in from the <tt>/proc</tt> or <tt>/sys</tt> file
  systems.  A <a href="http://code.google.com/p/macfuse/">MacFUSE</a>
  based <a href="http://osxbook.com/book/bonus/chapter11/procfs/">procfs
  filesystem for OS&nbsp;X</a> exists as well, but that is unlikely to be
  installed, and perhaps too cumbersome to set up for most users.)
</p>
<h3><a id="task-info-fun-with-mach-1" class="updatetitle">UPDATE 2010-01-12: Visibility
</a><br /></h3>
<div><p>
  A number of people have contacted me about
  the <code>sampling_fork</code> code example.  It has found its way
  into Will
  Drewry's <a href="http://github.com/redpig/patient0">patient0</a>
  and
  the <a href="http://codereview.chromium.org/549002">Chromium</a>
  browser.
</p>
</div>

]]></content:encoded>
			<comments>http://www.foldr.org/~michaelw/log/computers/macosx/task-info-fun-with-mach#writeback</comments>
		</item>

		<item>
			<title>NetNewsWire for your Feed-Reading Needs</title>
			<link>http://www.foldr.org/~michaelw/log/computers/macosx/netnewswire</link>
			<guid isPermaLink="true">http://www.foldr.org/~michaelw/log/computers/macosx/netnewswire</guid>
			<category>http://www.foldr.org/~michaelw/log/computers/macosx/</category>
			<pubDate>Wed, 25 Jun 2008 18:20:00 GMT</pubDate>
			<content:encoded><![CDATA[
<a href="http://www.newsgator.com/Individuals/NetNewsWire/"
title="More news, less junk. Faster."><img src="http://www.foldr.org/~michaelw/log/static/computers/macosx/netnewswire-badge.jpg"
height="31" width="88" alt="NetNewsWire: More news, less junk. Faster."
border="0" /></a>

<p>Reading news feeds?  Forget Safari.  Forget Apple Mail.  Instead,
try
out <a href="http://www.newsgator.com/Individuals/NetNewsWire/">NetNewsWire</a>:
It sports a convenient user interface <em>and</em> an integrated web browser
(via <a href="http://webkit.org/">WebKit</a>), need I say more?
</p>

<img src="http://www.foldr.org/~michaelw/log/static/computers/macosx/netnewswire.png"
     alt="NetNewsWire Screenshot"
     class="center" />

<p>I do not follow many news feeds, and after I switched
to <a href="http://www.apple.com/macosx/">MacOS&nbsp;X</a>, I used to
use Safari's built-in feed reader.  It was nothing to write home
about, but it has a simple user interface and worked well enough for
my modest needs.  With OS&nbsp;X&nbsp;10.5 <q>Leopard</q>, Apple Mail
grew RSS support and I switched to it as default feed reader.  I liked
that it was the same interface as for email, but some things were
rubbing me the wrong way.  For instance, I created a <em>Smart
Mailbox</em> to get rid of already read feed items:
<img src="http://www.foldr.org/~michaelw/log/static/computers/macosx/apple-mail-smart-mailbox.png" alt="Smart Mailbox in Apple
Mail" class="center" />
</p>

<p>The main show stopper was that some feeds basically require to
  visit a web page (e.g.,
  the <a href="http://newsrss.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml">BBC
  News feed</a> contains only a one-sentence summary of the stories.
  When in Apple Mail, this causes a switch to the default Web Browser,
  and possibly a desktop switch as well (thanks
  to <a href="http://www.apple.com/macosx/features/spaces.html">Spaces</a>).
</p>

<p>With NetNewsWire, the awkward application switching (and
  backswitching) is history.  Now, if only it could also
  view <a href="http://en.wikipedia.org/wiki/Portable_Document_Format">PDF</a>
  files inline
  (via <a href="http://developer.apple.com/cocoa/pdfkit.html">PDFKit</a>)...
</p>
]]></content:encoded>
			<comments>http://www.foldr.org/~michaelw/log/computers/macosx/netnewswire#writeback</comments>
		</item>

	</channel>
</rss>
