static int ListenUsingMach(size_t noteCount, const char **noteNames) // Implements the "listenMach" command. Register for the noteCount // notifications whose names are in the noteNames array. Then read // the notification Mach port, printing information about any // notifications that arrive. { int retVal; uint32_t noteErr; size_t noteIndex; int noteTokens[noteCount]; mach_port_t port = MACH_PORT_NULL; // Register. The first time around this loop fd == -1 and so we don't // specify NOTIFY_REUSE. notify_register_mach_port then allocates // a Mach port and returns it in port. For subsequent iterations // we /do/ specify NOTIFY_REUSE and notify_register_mach_port just // reuses the existing port. noteErr = NOTIFY_STATUS_OK; for (noteIndex = 0; noteIndex < noteCount; noteIndex++) { noteErr = notify_register_mach_port( noteNames[noteIndex], &port, (port == MACH_PORT_NULL) ? 0 : NOTIFY_REUSE, ¬eTokens[noteIndex] ); if (noteErr != NOTIFY_STATUS_OK) { break; } } if (noteErr != NOTIFY_STATUS_OK) { PrintNotifyError("registration failed", noteNames[noteIndex], noteErr); retVal = EXIT_FAILURE; } else { kern_return_t kr; mach_msg_empty_rcv_t msg; // Listen for and print any incoming notifications. fprintf(stdout, "Listening using Mach:\n"); fflush(stdout); do { msg.header.msgh_local_port = port; msg.header.msgh_size = sizeof(msg); kr = mach_msg_receive(&msg.header); if (kr == KERN_SUCCESS) { PrintToken(msg.header.msgh_id, noteCount, noteTokens, noteNames); } } while (kr == KERN_SUCCESS); fprintf(stderr, "error reading Mach message: %s (0x%x)\n", mach_error_string(kr), kr); retVal = EXIT_FAILURE; } return retVal; }
int OSMemoryNotificationCreate(OSMemoryNotificationRef *note) { OSMemoryNotificationRef ref = malloc(sizeof(struct _OSMemoryNotification)); if (NULL == ref) { return ENOMEM; } if (NOTIFY_STATUS_OK != notify_register_mach_port(kOSMemoryNotificationName, &ref->port, 0, &ref->token)) return ENOMEM; *note = ref; return 0; }
static int ListenUsingCoreFoundation(size_t noteCount, const char **noteNames) // Implements the "listenCF" command. Register for the noteCount // notifications whose names are in the noteNames array. Then wrap the // notification Mach port in a CFMachPort and use CF to read the notification // messages, printing the information about any notifications that arrive // from our CFMachPort callback. { int retVal; uint32_t noteErr; size_t noteIndex; int noteTokens[noteCount]; mach_port_t port = MACH_PORT_NULL; // Register. The first time around this loop fd == -1 and so we don't // specify NOTIFY_REUSE. notify_register_mach_port then allocates // a Mach port and returns it in port. For subsequent iterations // we /do/ specify NOTIFY_REUSE and notify_register_mach_port just // reuses the existing port. noteErr = NOTIFY_STATUS_OK; for (noteIndex = 0; noteIndex < noteCount; noteIndex++) { noteErr = notify_register_mach_port( noteNames[noteIndex], &port, (port == MACH_PORT_NULL) ? 0 : NOTIFY_REUSE, ¬eTokens[noteIndex] ); if (noteErr != NOTIFY_STATUS_OK) { break; } } if (noteErr != NOTIFY_STATUS_OK) { PrintNotifyError("registration failed", noteNames[noteIndex], noteErr); retVal = EXIT_FAILURE; } else { MyCFMachPortCallBackInfo myInfo; CFMachPortContext context = { 0 }; CFMachPortRef cfPort; Boolean shouldFreeInfo; CFRunLoopSourceRef rls; // Set up the context structure for MyCFMachPortCallBack. myInfo.magic = 'CFpI'; myInfo.noteCount = noteCount; myInfo.noteTokens = noteTokens; myInfo.noteNames = noteNames; // Create the CFMachPort. context.info = &myInfo; cfPort = CFMachPortCreateWithPort( NULL, port, MyCFMachPortCallBack, &context, &shouldFreeInfo ); assert(cfPort != NULL); // There can only be one CFMachPort for a given Mach port name. Thus, // if someone had already created a CFMachPort for "port", CFMachPort // would not create a new CFMachPort but, rather, return the existing // CFMachPort with the retain count bumped. In that case it hasn't // taken any 'reference' on the data in context; the context.info // on the /previous/ CFMachPort is still in use, but the context.info // that we supply is now superfluous. In that case it returns // shouldFreeInfo, telling us that we don't need to hold on to this // information. // // In this specific case no one should have already created a CFMachPort // for "port", so shouldFreeInfo should never be true. If it is, it's // time to worry! assert( ! shouldFreeInfo ); // Add it to the run loop. rls = CFMachPortCreateRunLoopSource(NULL, cfPort, 0); assert(rls != NULL); CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); CFRelease(rls); // Run the run loop. fprintf(stdout, "Listening using Core Foundation:\n"); fflush(stdout); CFRunLoopRun(); fprintf(stderr, "CFRunLoopRun returned\n"); retVal = EXIT_FAILURE; } return retVal; }