int main(void) { pthread_t pthread1, pthread2, pthread3; semaphore_t* sem = g_sem; kern_return_t kr; setbuf(stdout, NULL); kr = semaphore_create(mach_task_self(), &sem[0], SYNC_POLICY_FIFO, 0); OUT_ON_MACH_ERROR("semaphore_create", kr); kr = semaphore_create(mach_task_self(), &sem[1], SYNC_POLICY_FIFO, 0); OUT_ON_MACH_ERROR("semaphore_create", kr); (void)pthread_create(&pthread1, (const pthread_attr_t *)0, start_routine, (void *) 0); printf("created thread1=%lx\n", 0); (void)pthread_create(&pthread2, (const pthread_attr_t *)0, start_routine, (void *) 1); printf("created thread2=%lx\n", 1); (void)pthread_create(&pthread3, (const pthread_attr_t *)0, start_routine, (void *) 2); printf("created thread3=%lx\n", 2); // wait until all three threads are ready SEMAPHORE_WAIT(sem[1], 3); // printf("main: about to signal thread3\n"); // semaphore_signal_thread(sem[0], pthread_mach_thread_np(pthread3)); // wait for thread3 to sem_signal() // semaphore_wait(sem[1]); sleep(1); printf("main: about to signal all threads\n"); semaphore_signal_all(sem[0]); // wait for thread1 and thread2 to sem_signal() SEMAPHORE_WAIT(sem[1], 3); out: if (sem[0]) semaphore_destroy(mach_task_self(), sem[0]); if (sem[1]) semaphore_destroy(mach_task_self(), sem[1]); exit(kr); }
int semaphore_release(semaphore_t semaphore) { int result = 0; proc_t notify = NULL; int irq = __irq_save(); spinlock_acquire(&semaphore->lock); if (SEMAPHORE_WAIT(semaphore)) { ips_node_t node = SEMAPHORE_PTR(semaphore); IPS_NODE_WAIT_CLEAR(node); notify = IPS_NODE_PTR(node); node->next->prev = node->prev; node->prev->next = node->next; if (node->next == node) SEMAPHORE_WAIT_CLEAR(semaphore); else SEMAPHORE_PTR_SET(semaphore, node->next); result = 1; } else { ++ semaphore->count; } spinlock_release(&semaphore->lock); __irq_restore(irq); if (notify != NULL) proc_notify(notify); return result; }
uintptr_t semaphore_acquire(semaphore_t semaphore, ips_node_t node) { uintptr_t result; if (node == NULL) { ips_node_s node; result = semaphore_acquire(semaphore, &node); if (!result) ips_wait(&node); return result; } else { int irq = __irq_save(); spinlock_acquire(&semaphore->lock); result = semaphore->count; if (result > 0) { if (-- semaphore->count == 0) SEMAPHORE_WAIT_CLEAR(semaphore); spinlock_release(&semaphore->lock); __irq_restore(irq); IPS_NODE_WAIT_CLEAR(node); return result; } else { ips_wait_init(node, current); if (SEMAPHORE_WAIT(semaphore)) { node->next = SEMAPHORE_PTR(semaphore); node->prev = node->next->prev; node->next->prev = node; node->prev->next = node; } else { SEMAPHORE_WAIT_SET(semaphore); node->next = node->prev = node; SEMAPHORE_PTR_SET(semaphore, node); } spinlock_release(&semaphore->lock); __irq_restore(irq); return result; } } }
/* can be called from any thread */ static uint32 VCHAN_CC MyVirtualChannelWrite(uint32 openHandle, void * pData, uint32 dataLength, void * pUserData) { rdpChanMan * chan_man; struct chan_data * lchan; int index; chan_man = freerdp_chanman_find_by_open_handle(openHandle, &index); if ((chan_man == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT)) { DEBUG_CHANMAN("MyVirtualChannelWrite: error bad chanhan"); return CHANNEL_RC_BAD_CHANNEL_HANDLE; } if (!chan_man->is_connected) { DEBUG_CHANMAN("MyVirtualChannelWrite: error not connected"); return CHANNEL_RC_NOT_CONNECTED; } if (pData == 0) { DEBUG_CHANMAN("MyVirtualChannelWrite: error bad pData"); return CHANNEL_RC_NULL_DATA; } if (dataLength == 0) { DEBUG_CHANMAN("MyVirtualChannelWrite: error bad dataLength"); return CHANNEL_RC_ZERO_LENGTH; } lchan = chan_man->chans + index; if (lchan->flags != 2) { DEBUG_CHANMAN("MyVirtualChannelWrite: error not open"); return CHANNEL_RC_NOT_OPEN; } SEMAPHORE_WAIT(chan_man->sem); /* lock chan_man->sync* vars */ if (!chan_man->is_connected) { SEMAPHORE_POST(chan_man->sem); DEBUG_CHANMAN("MyVirtualChannelWrite: error not connected"); return CHANNEL_RC_NOT_CONNECTED; } chan_man->sync_data = pData; chan_man->sync_data_length = dataLength; chan_man->sync_user_data = pUserData; chan_man->sync_index = index; /* set the event */ freerdp_chanman_set_ev(chan_man); return CHANNEL_RC_OK; }
static uint32 VCHAN_CC MyVirtualChannelEventPush(uint32 openHandle, RD_EVENT * event) { rdpChanMan * chan_man; struct chan_data * lchan; int index; chan_man = freerdp_chanman_find_by_open_handle(openHandle, &index); if ((chan_man == NULL) || (index < 0) || (index >= CHANNEL_MAX_COUNT)) { DEBUG_CHANMAN("MyVirtualChannelEventPush: error bad chanhan"); return CHANNEL_RC_BAD_CHANNEL_HANDLE; } if (!chan_man->is_connected) { DEBUG_CHANMAN("MyVirtualChannelEventPush: error not connected"); return CHANNEL_RC_NOT_CONNECTED; } if (event == NULL) { DEBUG_CHANMAN("MyVirtualChannelEventPush: error bad event"); return CHANNEL_RC_NULL_DATA; } lchan = chan_man->chans + index; if (lchan->flags != 2) { DEBUG_CHANMAN("MyVirtualChannelEventPush: error not open"); return CHANNEL_RC_NOT_OPEN; } SEMAPHORE_WAIT(chan_man->sem_event); /* lock chan_man->event */ if (!chan_man->is_connected) { SEMAPHORE_POST(chan_man->sem_event); DEBUG_CHANMAN("MyVirtualChannelEventPush: error not connected"); return CHANNEL_RC_NOT_CONNECTED; } chan_man->event = event; /* set the event */ freerdp_chanman_set_ev(chan_man); return CHANNEL_RC_OK; }