static void test_io_close(int with_timer, bool from_path) { #define chunks 4 #define READSIZE (512*1024) unsigned int i; const char *path = LARGE_FILE; int fd = open(path, O_RDONLY); if (fd == -1) { if (errno == ENOENT) { test_skip("Large file not found"); return; } test_errno("open", errno, 0); test_stop(); } #ifdef F_GLOBAL_NOCACHE if (fcntl(fd, F_GLOBAL_NOCACHE, 1) == -1) { test_errno("fcntl F_GLOBAL_NOCACHE", errno, 0); test_stop(); } #endif struct stat sb; if (fstat(fd, &sb)) { test_errno("fstat", errno, 0); test_stop(); } const size_t size = (size_t)sb.st_size / chunks; const int expected_error = with_timer? ECANCELED : 0; dispatch_source_t t = NULL; dispatch_group_t g = dispatch_group_create(); dispatch_group_enter(g); void (^cleanup_handler)(int error) = ^(int error) { test_errno("create error", error, 0); dispatch_group_leave(g); close(fd); }; dispatch_io_t io; if (!from_path) { io = dispatch_io_create(DISPATCH_IO_RANDOM, fd, dispatch_get_global_queue(0, 0), cleanup_handler); } else { #if DISPATCHTEST_IO_PATH io = dispatch_io_create_with_path(DISPATCH_IO_RANDOM, path, O_RDONLY, 0, dispatch_get_global_queue(0, 0), cleanup_handler); #endif } dispatch_io_set_high_water(io, READSIZE); if (with_timer == 1) { dispatch_io_set_low_water(io, READSIZE); dispatch_io_set_interval(io, 2 * NSEC_PER_SEC, DISPATCH_IO_STRICT_INTERVAL); } else if (with_timer == 2) { t = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0,0)); dispatch_retain(io); dispatch_source_set_event_handler(t, ^{ dispatch_io_close(io, DISPATCH_IO_STOP); dispatch_source_cancel(t); });
data ( const data &other ) : native( other.native ) { XDISPATCH_ASSERT( native ); dispatch_retain( native ); }
group::group ( const group &other ) : object( other ), m_native( other.m_native ) { XDISPATCH_ASSERT( m_native ); dispatch_retain( m_native ); }
group::group ( dispatch_group_t g ) : object(), m_native( g ) { XDISPATCH_ASSERT( m_native ); dispatch_retain( m_native ); }
queue::queue ( const queue &other ) : m_native( other.m_native ), m_label( other.m_label ) { XDISPATCH_ASSERT( m_native ); dispatch_retain( m_native ); }
semaphore::semaphore ( dispatch_semaphore_t sem ) : d( new data ) { XDISPATCH_ASSERT( sem ); XDISPATCH_ASSERT( d.get() ); d->native = sem; dispatch_retain( sem ); }
int OSMemoryNotificationTimedWait(OSMemoryNotificationRef note, OSMemoryNotificationLevel *level, const struct timeval *abstime) { dispatch_semaphore_t sema = dispatch_semaphore_create(0); dispatch_retain(sema); dispatch_source_t memoryNotificationSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_VM, 0, DISPATCH_VM_PRESSURE, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); dispatch_source_set_event_handler(memoryNotificationSource, ^{ dispatch_semaphore_signal(sema); dispatch_release(sema); });
__XDISPATCH_USE_NAMESPACE queue::queue ( dispatch_queue_t q ) : m_native( q ), m_label( dispatch_queue_get_label( q ) ) { XDISPATCH_ASSERT( m_native ); dispatch_retain( m_native ); }
static VALUE rb_queue_init(VALUE self, SEL sel, VALUE name) { StringValue(name); rb_queue_t *queue = RQueue(self); queue->should_release_queue = 1; queue->queue = dispatch_queue_create(RSTRING_PTR(name), NULL); assert(queue->queue != NULL); dispatch_retain(queue->queue); return self; }
queue::queue ( dispatch_queue_t q ) : object(), d( new data ) { XDISPATCH_ASSERT( d.get() ); dispatch_retain( q ); d->native = q; XDISPATCH_ASSERT( d->native ); d->label = std::string( dispatch_queue_get_label( q ) ); }
group & group::operator = ( const group &other ) { if( *this != other ) { object::operator = ( other ); m_native = other.m_native; XDISPATCH_ASSERT( m_native ); dispatch_retain( m_native ); } return *this; }
xdispatch::queue & queue::operator = ( const queue &other ) { if( *this != other ) { object::operator = ( other ); m_native = other.m_native; XDISPATCH_ASSERT( m_native ); dispatch_retain( m_native ); m_label = other.m_label; } return *this; }
static Boolean __SCPreferencesScheduleWithRunLoop(SCPreferencesRef prefs, CFRunLoopRef runLoop, CFStringRef runLoopMode, dispatch_queue_t queue) { Boolean ok = FALSE; SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; pthread_mutex_lock(&prefsPrivate->lock); if ((prefsPrivate->dispatchQueue != NULL) || // if we are already scheduled on a dispatch queue ((queue != NULL) && prefsPrivate->scheduled)) { // if we are already scheduled on a CFRunLoop _SCErrorSet(kSCStatusInvalidArgument); goto done; } if (!prefsPrivate->scheduled) { CFMutableArrayRef keys; if (prefsPrivate->session == NULL) { ok = __SCPreferencesAddSession(prefs); if (!ok) { goto done; } } CFRetain(prefs); // hold a reference to the prefs keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); CFArrayAppendValue(keys, prefsPrivate->sessionKeyCommit); CFArrayAppendValue(keys, prefsPrivate->sessionKeyApply); (void) SCDynamicStoreSetNotificationKeys(prefsPrivate->session, keys, NULL); CFRelease(keys); if (runLoop != NULL) { prefsPrivate->rls = SCDynamicStoreCreateRunLoopSource(NULL, prefsPrivate->session, 0); prefsPrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } prefsPrivate->scheduled = TRUE; } if (queue != NULL) { ok = SCDynamicStoreSetDispatchQueue(prefsPrivate->session, queue); if (!ok) { prefsPrivate->scheduled = FALSE; (void) SCDynamicStoreSetNotificationKeys(prefsPrivate->session, NULL, NULL); CFRelease(prefs); goto done; } prefsPrivate->dispatchQueue = queue; dispatch_retain(prefsPrivate->dispatchQueue); } else { if (!_SC_isScheduled(NULL, runLoop, runLoopMode, prefsPrivate->rlList)) { /* * if we do not already have notifications scheduled with * this runLoop / runLoopMode */ CFRunLoopAddSource(runLoop, prefsPrivate->rls, runLoopMode); } _SC_schedule(prefs, runLoop, runLoopMode, prefsPrivate->rlList); } ok = TRUE; done : pthread_mutex_unlock(&prefsPrivate->lock); return ok; }
Boolean SCDynamicStoreSetDispatchQueue(SCDynamicStoreRef store, dispatch_queue_t queue) { dispatch_group_t drainGroup = NULL; dispatch_queue_t drainQueue = NULL; dispatch_group_t group = NULL; mach_port_t mp; Boolean ok = FALSE; dispatch_source_t source; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; if (store == NULL) { // sorry, you must provide a session _SCErrorSet(kSCStatusNoStoreSession); return FALSE; } if (queue == NULL) { if (storePrivate->dispatchQueue == NULL) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } ok = TRUE; goto cleanup; } if (storePrivate->server == MACH_PORT_NULL) { // sorry, you must have an open session to play _SCErrorSet(kSCStatusNoStoreServer); return FALSE; } if ((storePrivate->dispatchQueue != NULL) || (storePrivate->rls != NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } if (storePrivate->notifyStatus != NotifierNotRegistered) { // sorry, you can only have one notification registered at once... _SCErrorSet(kSCStatusNotifierActive); return FALSE; } /* * mark our using of the SCDynamicStore notifications, create and schedule * the notification port (storePrivate->rlsNotifyPort), and a bunch of other * "setup" */ storePrivate->notifyStatus = Using_NotifierInformViaDispatch; rlsSchedule((void*)store, NULL, NULL); if (storePrivate->rlsNotifyPort == NULL) { /* if we could not schedule the notification */ _SCErrorSet(kSCStatusFailed); goto cleanup; } // retain the dispatch queue storePrivate->dispatchQueue = queue; dispatch_retain(storePrivate->dispatchQueue); // // We've taken a reference to the callers dispatch_queue and we // want to hold on to that reference until we've processed any/all // notifications. To facilitate this we create a group, dispatch // any notification blocks to via that group, and when the caller // has told us to stop the notifications (unschedule) we wait for // the group to empty and use the group's finalizer to release // our reference to the SCDynamicStore. // group = dispatch_group_create(); storePrivate->dispatchGroup = group; CFRetain(store); dispatch_set_context(storePrivate->dispatchGroup, (void *)store); dispatch_set_finalizer_f(storePrivate->dispatchGroup, (dispatch_function_t)CFRelease); // create a dispatch source for the mach notifications mp = CFMachPortGetPort(storePrivate->rlsNotifyPort); source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0, queue); if (source == NULL) { SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore dispatch_source_create() failed")); _SCErrorSet(kSCStatusFailed); goto cleanup; } dispatch_source_set_event_handler(source, ^{ kern_return_t kr; mach_msg_id_t msgid; union { u_int8_t buf[sizeof(mach_msg_empty_t) + MAX_TRAILER_SIZE]; mach_msg_empty_rcv_t msg; mach_no_senders_notification_t no_senders; } notify_msg; kr = mach_msg(¬ify_msg.msg.header, // msg MACH_RCV_MSG, // options 0, // send_size sizeof(notify_msg), // rcv_size mp, // rcv_name MACH_MSG_TIMEOUT_NONE, // timeout MACH_PORT_NULL); // notify if (kr != KERN_SUCCESS) { SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore notification handler, kr=0x%x"), kr); return; } msgid = notify_msg.msg.header.msgh_id; CFRetain(store); dispatch_group_async(group, queue, ^{ if (msgid == MACH_NOTIFY_NO_SENDERS) { // re-establish notification and inform the client (void)__SCDynamicStoreReconnectNotifications(store); } rlsPerform(storePrivate); CFRelease(store); }); });
__private_extern__ Boolean __SCDynamicStoreReconnectNotifications(SCDynamicStoreRef store) { dispatch_queue_t dispatchQueue = NULL; __SCDynamicStoreNotificationStatus notifyStatus; Boolean ok = TRUE; CFArrayRef rlList = NULL; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; // save old SCDynamicStore [notification] state notifyStatus = storePrivate->notifyStatus; // before tearing down our [old] notifications, make sure we've // retained any information that will be lost when we cancel the // current no-longer-valid handler switch (notifyStatus) { case Using_NotifierInformViaRunLoop : if (storePrivate->rlList != NULL) { rlList = CFArrayCreateCopy(NULL, storePrivate->rlList); } case Using_NotifierInformViaDispatch : dispatchQueue = storePrivate->dispatchQueue; if (dispatchQueue != NULL) dispatch_retain(dispatchQueue); break; default : break; } // cancel [old] notifications if (!SCDynamicStoreNotifyCancel(store)) { // if we could not cancel / reconnect SCLog(TRUE, LOG_DEBUG, CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreNotifyCancel() failed: %s"), SCErrorString(SCError())); } // set notification keys & patterns if ((storePrivate->keys != NULL) || (storePrivate->patterns)) { ok = SCDynamicStoreSetNotificationKeys(store, storePrivate->keys, storePrivate->patterns); if (!ok) { SCLog((SCError() != BOOTSTRAP_UNKNOWN_SERVICE), LOG_ERR, CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreSetNotificationKeys() failed")); goto done; } } switch (notifyStatus) { case Using_NotifierInformViaRunLoop : { CFIndex i; CFIndex n; CFRunLoopSourceRef rls; rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0); if (rls == NULL) { SCLog((SCError() != BOOTSTRAP_UNKNOWN_SERVICE), LOG_ERR, CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreCreateRunLoopSource() failed")); ok = FALSE; break; } n = (rlList != NULL) ? CFArrayGetCount(rlList) : 0; for (i = 0; i < n; i += 3) { CFRunLoopRef rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1); CFStringRef rlMode = (CFStringRef) CFArrayGetValueAtIndex(rlList, i+2); CFRunLoopAddSource(rl, rls, rlMode); } CFRelease(rls); break; } case Using_NotifierInformViaDispatch : ok = SCDynamicStoreSetDispatchQueue(store, dispatchQueue); if (!ok) { SCLog((SCError() != BOOTSTRAP_UNKNOWN_SERVICE), LOG_ERR, CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreSetDispatchQueue() failed")); goto done; } break; default : _SCErrorSet(kSCStatusFailed); ok = FALSE; break; } done : // cleanup switch (notifyStatus) { case Using_NotifierInformViaRunLoop : if (rlList != NULL) CFRelease(rlList); break; case Using_NotifierInformViaDispatch : if (dispatchQueue != NULL) dispatch_release(dispatchQueue); break; default : break; } if (!ok) { SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore server %s, notification (%s) not restored"), (SCError() == BOOTSTRAP_UNKNOWN_SERVICE) ? "shutdown" : "failed", notifyType[notifyStatus]); } // inform the client pushDisconnect(store); return ok; }
int main(int argc, char** argv) { struct hostent *he; int sockfd, clientfd; struct sockaddr_in addr1, addr2, server; socklen_t addr2len; socklen_t addr1len; pid_t clientid; const char *path = "/usr/share/dict/words"; int read_fd, fd; if (argc == 2) { // Client dispatch_test_start(NULL); if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { test_errno("Client-socket()", errno, 0); test_stop(); } if ((he = gethostbyname("localhost")) == NULL) { fprintf(stderr, "Client-gethostbyname() failed\n"); test_stop(); } memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length); server.sin_family = AF_INET; server.sin_port = atoi(argv[1]); fprintf(stderr, "Client-connecting on port ... %d\n", server.sin_port); if (connect(sockfd, (struct sockaddr *)&server, sizeof(server))) { test_errno("client-connect()", errno, 0); test_stop(); } // Read from the socket and compare the contents are what we expect fd = open(path, O_RDONLY); if (fd == -1) { test_errno("client-open", errno, 0); test_stop(); } #ifdef F_NOCACHE if (fcntl(fd, F_NOCACHE, 1)) { test_errno("client-fcntl F_NOCACHE", errno, 0); test_stop(); } #else // investigate what the impact of lack of file cache disabling has // for this test #endif struct stat sb; if (fstat(fd, &sb)) { test_errno("client-fstat", errno, 0); test_stop(); } size_t size = sb.st_size; __block dispatch_data_t g_d1 = dispatch_data_empty; __block dispatch_data_t g_d2 = dispatch_data_empty; __block int g_error = 0; dispatch_group_t g = dispatch_group_create(); dispatch_group_enter(g); dispatch_read(fd, size, dispatch_get_global_queue(0, 0), ^(dispatch_data_t d1, int error) { test_errno("Client-dict-read error", error, 0); test_long("Client-dict-dispatch data size", dispatch_data_get_size(d1), size); dispatch_retain(d1); g_d1 = d1; dispatch_group_leave(g); });