Section 6.3. A Flavor of the Mach APIs


6.3. A Flavor of the Mach APIs

Let us look at a few simple examples of using the Mach APIs. These will serve as a prelude to more complex or subsystem-specific examples that we will see later in this chapter and in subsequent chapters.

Documentation for most Mach calls exported by the xnu kernel is available in the osfmk/man/ directory within the xnu package. You might find it useful to test API-based examples while referring to the API documentation.


6.3.1. Displaying Host Information

The host_info() Mach call retrieves information about a host, such as the type and number of processors installed, the number of processors currently available, and the memory size. As is the case with many Mach "info" calls, host_info() takes a flavor argument, which specifies the kind of information to be retrieved. For example, host_info() accepts the HOST_BASIC_INFO, HOST_SCHED_INFO, and HOST_PRIORITY_INFO flavors as arguments to return basic, scheduler-related, and scheduler-priority-related information, respectively, from the kernel. Besides host_info(), other calls such as host_kernel_version(), host_get_boot_info(), and host_page_size() can be used to retrieve miscellaneous information. Figure 61 shows an example of using the host_info() call.

Figure 61. Retrieving basic host information using Mach calls

// host_basic_info.c #include <stdio.h> #include <stdlib.h> #include <mach/mach.h> #define EXIT_ON_MACH_ERROR(msg, retval) \     if (kr != KERN_SUCCESS) { mach_error(msg ":" , kr); exit((retval)); } int main() {     kern_return_t           kr; // the standard return type for Mach calls     host_name_port_t        myhost;     kernel_version_t        kversion;     host_basic_info_data_t  hinfo;     mach_msg_type_number_t  count;     char                   *cpu_type_name, *cpu_subtype_name;     vm_size_t               page_size;     // get send rights to the name port for the current host     myhost = mach_host_self();     kr = host_kernel_version(myhost, kversion);     EXIT_ON_MACH_ERROR("host_kernel_version", kr);     count = HOST_BASIC_INFO_COUNT;      // size of the buffer     kr = host_info(myhost,              // the host name port                    HOST_BASIC_INFO,     // flavor                    (host_info_t)&hinfo, // out structure                    &count);             // in/out size     EXIT_ON_MACH_ERROR("host_info", kr);     kr = host_page_size(myhost, &page_size);     EXIT_ON_MACH_ERROR("host_page_size", kr);     printf("%s\n", kversion);     // the slot_name() library function converts the specified     // cpu_type/cpu_subtype pair to a human-readable form     slot_name(hinfo.cpu_type, hinfo.cpu_subtype, &cpu_type_name,               &cpu_subtype_name);     printf("cpu              %s (%s, type=0x%x subtype=0x%x "            "threadtype=0x%x)\n", cpu_type_name, cpu_subtype_name,            hinfo.cpu_type, hinfo.cpu_subtype, hinfo.cpu_threadtype);     printf("max_cpus         %d\n", hinfo.max_cpus);     printf("avail_cpus       %d\n", hinfo.avail_cpus);     printf("physical_cpu     %d\n", hinfo.physical_cpu);     printf("physical_cpu_max %d\n", hinfo.physical_cpu_max);     printf("logical_cpu      %d\n", hinfo.logical_cpu);     printf("logical_cpu_max  %d\n", hinfo.logical_cpu_max);     printf("memory_size      %u MB\n", (hinfo.memory_size >> 20));     printf("max_mem          %llu MB\n", (hinfo.max_mem >> 20));     printf("page_size        %u bytes\n", page_size);     exit(0); } $ gcc -Wall -o host_basic_info host_basic_info.c $ ./host_basic_info # Power Mac G5 Quad 2.5GHz Darwin Kernel Version 8.5.0: ... root:xnu-792.6.61.obj~1/RELEASE_PPC cpu              ppc970 (PowerPC 970, type=0x12 subtype=0x64 threadtype=0x0) max_cpus         4 avail_cpus       4 physical_cpu     4 physical_cpu_max 4 logical_cpu      4 logical_cpu_max  4 memory_size      2048 MB max_mem          4096 MB page_size        4096 bytes $ ./host_basic_info # iMac Core Duo 1.83GHz Darwin Kernel Version 8.5.1: ... root:xnu-792.8.36.obj~1/RELEASE_I386 cpu              i486 (Intel 80486, type=0x7, subtype=0x4, threadtype=0x0) max_cpus         2 avail_cpus       2 ... page_size        4096 bytes

Note in Figure 61 that as discussed in Chapter 5, the memory_size value reported by Mach is pinned to 2GB on a machine with more than 2GB of physical memory.

6.3.2. Accessing the Kernel's Clock Services

The kernel provides clock services with different clock types such as system, calendar, and real time. Accessing these services involves acquiring send rights to their ports and sending messages requesting the clocks' attributes or functionality. Figure 62 shows a program that retrieves the attributes and current time values from the kernel's various clocks.

Figure 62. Retrieving clock attributes and time values in Mach

// host_clock.c #include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <mach/mach.h> #include <mach/clock.h> #define OUT_ON_MACH_ERROR(msg, retval) \     if (kr != KERN_SUCCESS) { mach_error(msg ":" , kr); goto out; } int main() {     kern_return_t          kr;     host_name_port_t       myhost;     clock_serv_t           clk_system, clk_calendar, clk_realtime;     natural_t              attribute[4];     mach_msg_type_number_t count;     mach_timespec_t        timespec;     struct timeval         t;     myhost = mach_host_self();     // Get a send right to the system clock's name port     kr = host_get_clock_service(myhost,  SYSTEM_CLOCK,                                 (clock_serv_t *)&clk_system);     OUT_ON_MACH_ERROR("host_get_clock_service", kr);     // Get a send right to the calendar clock's name port     kr = host_get_clock_service(myhost, CALENDAR_CLOCK,                                 (clock_serv_t *)&clk_calendar);     OUT_ON_MACH_ERROR("host_get_clock_service", kr);     // Get a send right to the real-time clock's name port     kr = host_get_clock_service(myhost, REALTIME_CLOCK,                                 (clock_serv_t *)&clk_realtime);     OUT_ON_MACH_ERROR("host_get_clock_service", kr);     //// System clock     count = sizeof(attribute)/sizeof(natural_t);     // Get the clock's resolution in nanoseconds     kr = clock_get_attributes(clk_system, CLOCK_GET_TIME_RES,                               (clock_attr_t)attribute, &count);     OUT_ON_MACH_ERROR("clock_get_attributes", kr);     // Get the current time     kr = clock_get_time(clk_system, &timespec);     OUT_ON_MACH_ERROR("clock_get_time", kr);     printf("System clock  : %u s + %u ns (res %u ns)\n",            timespec.tv_sec, timespec.tv_nsec, attribute[0]);     //// Real-time clock     count = sizeof(attribute)/sizeof(natural_t);     kr = clock_get_attributes(clk_realtime, CLOCK_GET_TIME_RES,                               (clock_attr_t)&attribute, &count);     OUT_ON_MACH_ERROR("clock_get_attributes", kr);     kr = clock_get_time(clk_realtime, &timespec);     OUT_ON_MACH_ERROR("clock_get_time", kr);     printf("Realtime clock: %u s + %u ns (res %u ns)\n",            timespec.tv_sec, timespec.tv_nsec, attribute[0]);     //// Calendar clock     count = sizeof(attribute)/sizeof(natural_t);     kr = clock_get_attributes(clk_calendar, CLOCK_GET_TIME_RES,                               (clock_attr_t)&attribute, &count);     OUT_ON_MACH_ERROR("clock_get_attributes", kr);     kr = clock_get_time(clk_calendar, &timespec);     gettimeofday(&t, NULL);     OUT_ON_MACH_ERROR("clock_get_time", kr);     printf("Calendar clock: %u s + %u ns (res %u ns)\n",            timespec.tv_sec, timespec.tv_nsec, attribute[0]);     printf("gettimeofday  : %ld s + %d us\n", t.tv_sec, t.tv_usec); out:     // Should deallocate ports here for cleanliness     mach_port_deallocate(mach_task_self(), myhost);     mach_port_deallocate(mach_task_self(), clk_calendar);     mach_port_deallocate(mach_task_self(), clk_system);     mach_port_deallocate(mach_task_self(), clk_realtime);     exit(0); } $ gcc -Wall -o host_clock host_clock.c $ ./host_clock System clock  : 134439 s + 840456243 ns (res 10000000 ns) Realtime clock: 134439 s + 841218705 ns (res 10000000 ns) Calendar clock: 1104235237 s + 61156000 ns (res 10000000 ns) gettimeofday  : 1104235237 s + 61191 us

6.3.3. Using a Clock Service to Ring an Alarm

Having seen how to acquire send rights to a clock service's port, we can use these rights to request the service to ring an alarm at a specified time. The clock will notify us by sending an IPC message when the alarm is fired. The program shown in Figure 63 sets an alarm to ring after 2.5 seconds and waits for the alarm message to arrive on a port it allocated.

Figure 63. Setting an alarm using Mach calls

// host_alarm.c #include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <mach/mach.h> #include <mach/clock.h> #define OUT_ON_MACH_ERROR(msg, retval) \     if (kr != KERN_SUCCESS) { mach_error(msg ":" , kr); goto out; } // Structure for the IPC message we will receive from the clock typedef struct msg_format_recv_s {     mach_msg_header_t  header;     int                data;     mach_msg_trailer_t trailer; } msg_format_recv_t; int main() {     kern_return_t     kr;     clock_serv_t      clk_system;     mach_timespec_t   alarm_time;     clock_reply_t     alarm_port;     struct timeval    t1, t2;     msg_format_recv_t message;     mach_port_t       mytask;     // The C library optimized this call by returning the task port's value     // that it caches in the mach_task_self_ variable     mytask = mach_task_self();     kr = host_get_clock_service(mach_host_self(), SYSTEM_CLOCK,                                 (clock_serv_t *)&clk_system);     OUT_ON_MACH_ERROR("host_get_clock_service", kr);     // Let us set the alarm to ring after 2.5 seconds     alarm_time.tv_sec = 2;     alarm_time.tv_nsec = 50000000;     // Allocate a port (specifically, get receive right for the new port)     // We will use this port to receive the alarm message from the clock     kr = mach_port_allocate(              mytask,                  // the task acquiring the port right              MACH_PORT_RIGHT_RECEIVE, // type of right              &alarm_port);            // task's name for the port right     OUT_ON_MACH_ERROR("mach_port_allocate", kr);     gettimeofday(&t1, NULL);     // Set the alarm     kr = clock_alarm(clk_system,    // the clock to use                      TIME_RELATIVE, // how to interpret alarm time                      alarm_time,    // the alarm time                      alarm_port);   // this port will receive the alarm message     OUT_ON_MACH_ERROR("clock_alarm", kr);     printf("Current time %ld s + %d us\n"            "Setting alarm to ring after %d s + %d ns\n",            t1.tv_sec, t1.tv_usec, alarm_time.tv_sec, alarm_time.tv_nsec);     // Wait to receive the alarm message (we will block here)     kr = mach_msg(&(message.header),       // the message buffer                   MACH_RCV_MSG,            // message option bits                   0,                       // send size (we are receiving, so 0)                   message.header.msgh_size,// receive limit                   alarm_port,              // receive right                   MACH_MSG_TIMEOUT_NONE,   // no timeout                   MACH_PORT_NULL);         // no timeout notification port     // We should have received an alarm message at this point     gettimeofday(&t2, NULL);     OUT_ON_MACH_ERROR("mach_msg", kr);     if (t2.tv_usec < t1.tv_usec) {         t1.tv_sec += 1;         t1.tv_usec -= 1000000;     }     printf("\nCurrent time %ld s + %d us\n", t2.tv_sec, t2.tv_usec);     printf("Alarm rang after %ld s + %d us\n", (t2.tv_sec - t1.tv_sec),           (t2.tv_usec - t1.tv_usec)); out:     mach_port_deallocate(mytask, clk_system);     // Release user reference for the receive right we created     mach_port_deallocate(mytask, alarm_port);     exit(0); } $ gcc -Wall -o host_alarm host_alarm.c $ ./host_alarm Current time 1104236281 s + 361257 us Setting alarm to ring after 2 s + 50000000 ns Current time 1104236283 s + 412115 us Alarm rang after 2 s + 50858 us

6.3.4. Displaying Host Statistics

The host_statistics() call can be used to retrieve statistical information about processor and virtual memory usage on a system-wide basis. Figure 64 shows an example of using this call.

Figure 64. Using Mach calls to retrieve scheduling and virtual memory statistics

// host_statistics.c #include <stdio.h> #include <stdlib.h> #include <mach/mach.h> // Wrapper function with error checking kern_return_t do_host_statistics(host_name_port_t        host,                    host_flavor_t           flavor,                    host_info_t             info,                    mach_msg_type_number_t *count) {     kern_return_t kr;     kr = host_statistics(host,              // control port for the host                          flavor,            // type of statistics desired                          (host_info_t)info, // out buffer                          count);            // in/out size of buffer     if (kr != KERN_SUCCESS) {         (void)mach_port_deallocate(mach_task_self(), host);         mach_error("host_info:", kr);         exit(1);     }     return kr; } int main() {     kern_return_t             kr;     host_name_port_t          host;     mach_msg_type_number_t    count;     vm_size_t                 page_size;     host_load_info_data_t     load_info;     host_cpu_load_info_data_t cpu_load_info;     vm_statistics_data_t      vm_stat;     host = mach_host_self();     count = HOST_LOAD_INFO_COUNT;     // Get system loading statistics     kr = do_host_statistics(host, HOST_LOAD_INFO, (host_info_t)&load_info,                             &count);     count = HOST_VM_INFO_COUNT;     // Get virtual memory statistics     kr = do_host_statistics(host, HOST_VM_INFO, (host_info_t)&vm_stat, &count);     count = HOST_CPU_LOAD_INFO_COUNT;     // Get CPU load statistics     kr = do_host_statistics(host, HOST_CPU_LOAD_INFO,                             (host_info_t)&cpu_load_info, &count);     kr = host_page_size(host, &page_size);     printf("Host statistics:\n");     // (average # of runnable processes) / (# of CPUs)     printf("Host load statistics\n");     printf("  time period (sec) %5s%10s%10s\n", "5", "30", "60");     printf("  load average %10u%10u%10u\n", load_info.avenrun[0],            load_info.avenrun[1], load_info.avenrun[2]);     printf("  Mach factor %10u%10u%10u\n", load_info.mach_factor[0],            load_info.mach_factor[1], load_info.mach_factor[2]);     printf("\n");     printf("Cumulative CPU load statistics\n");     printf("  User state ticks     = %u\n",            cpu_load_info.cpu_ticks[CPU_STATE_USER]);     printf("  System state ticks   = %u\n",            cpu_load_info.cpu_ticks[CPU_STATE_SYSTEM]);     printf("  Nice state ticks     = %u\n",            cpu_load_info.cpu_ticks[CPU_STATE_NICE]);     printf("  Idle state ticks     = %u\n",            cpu_load_info.cpu_ticks[CPU_STATE_IDLE]);     printf("\n");     printf("Virtual memory statistics\n");     printf("  page size            = %u bytes\n", page_size);     printf("  pages free           = %u\n", vm_stat.free_count);     printf("  pages active         = %u\n", vm_stat.active_count);     printf("  pages inactive       = %u\n", vm_stat.inactive_count);     printf("  pages wired down     = %u\n", vm_stat.wire_count);     printf("  zero fill pages      = %u\n", vm_stat.zero_fill_count);     printf("  pages reactivated    = %u\n", vm_stat.reactivations);     printf("  pageins              = %u\n", vm_stat.pageins);     printf("  pageouts             = %u\n", vm_stat.pageouts);     printf("  translation faults   = %u\n", vm_stat.faults);     printf("  copy-on-write faults = %u\n", vm_stat.cow_faults);     printf("  object cache lookups = %u\n", vm_stat.lookups);     printf("  object cache hits    = %u (hit rate %2.2f %%)\n", vm_stat.hits,            100 * (double)vm_stat.hits/(double)vm_stat.lookups);     exit(0); } $ gcc -Wall -o host_statistics host_statistics.c $ ./host_statistics Host statistics: Host load statistics   time period (sec)     5        30        60   load average        276       233        70   Mach factor        1685      1589      1609 Cumulative CPU load statistics   User state ticks     = 109098   System state ticks   = 41056   Nice state ticks     = 535   Idle state ticks     = 1974855 Virtual memory statistics   page size            = 4096 bytes   pages free           = 434154   pages active         = 70311   pages inactive       = 236301   pages wired down     = 45666   zero fill pages      = 2266643   pages reactivated    = 0   pageins              = 55952   pageouts             = 0   translation faults   = 4549671   copy-on-write faults = 83912   object cache lookups = 36028   object cache hits    = 19120 (hit rate 53.07 %)




Mac OS X Internals. A Systems Approach
Mac OS X Internals: A Systems Approach
ISBN: 0321278542
EAN: 2147483647
Year: 2006
Pages: 161
Authors: Amit Singh

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net