this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Reworked Mach semaphores

+175 -25
+49
src/libSystem/kernel-mach/FutexSemaphore.cpp
··· 1 + #include "FutexSemaphore.h" 2 + #include "Futex.h" 3 + #include <linux/futex.h> 4 + #include "../../util/log.h" 5 + 6 + Darling::FutexSemaphore::FutexSemaphore(int value) 7 + : m_counter(value), m_waiting(0) 8 + { 9 + } 10 + 11 + void Darling::FutexSemaphore::signal() 12 + { 13 + if (__sync_fetch_and_add(&m_counter, 1) == 0) 14 + Futex::futex(&m_counter, FUTEX_WAKE, 1); 15 + } 16 + 17 + void Darling::FutexSemaphore::signalAll() 18 + { 19 + if (m_waiting > 0) 20 + { 21 + int count = m_waiting; 22 + 23 + m_counter = count; 24 + //LOG << "Signalling " << count << " threads\n"; 25 + Futex::futex(&m_counter, FUTEX_WAKE, count); 26 + } 27 + } 28 + 29 + void Darling::FutexSemaphore::wait() 30 + { 31 + while (true) 32 + { 33 + int value = m_counter; 34 + if (value > 0) 35 + { 36 + //LOG << "Value is " << value << ", trying to decrement\n"; 37 + if (__sync_bool_compare_and_swap(&m_counter, value, value-1)) 38 + break; 39 + } 40 + else 41 + { 42 + __sync_fetch_and_add(&m_waiting, 1); 43 + Futex::futex(&m_counter, FUTEX_WAIT, value); 44 + __sync_fetch_and_sub(&m_waiting, 1); 45 + } 46 + } 47 + } 48 + 49 +
+22
src/libSystem/kernel-mach/FutexSemaphore.h
··· 1 + #ifndef FUTEXSEMAPHORE_H 2 + #define FUTEXSEMAPHORE_H 3 + 4 + namespace Darling { 5 + 6 + class FutexSemaphore 7 + { 8 + public: 9 + FutexSemaphore(int value); 10 + void signal(); 11 + 12 + // This seems to be inherently broken 13 + void signalAll(); 14 + void wait(); 15 + private: 16 + int m_counter; 17 + int m_waiting; 18 + }; 19 + 20 + } 21 + 22 + #endif
+17 -24
src/libSystem/kernel-mach/semaphore.cpp
··· 5 5 #include "trace.h" 6 6 #include <unistd.h> 7 7 #include <errno.h> 8 + #include "FutexSemaphore.h" 8 9 9 10 kern_return_t semaphore_create(darwin_task_t task, esemaphore_t *semaphore, int policy, int value) 10 11 { 11 12 TRACE4(task, semaphore, policy, value); 12 13 CHECK_TASK_SELF(task); 14 + 15 + if (value < 0) 16 + return KERN_INVALID_ARGUMENT; 13 17 14 18 if (!semaphore) 15 19 return KERN_INVALID_ARGUMENT; ··· 17 21 *semaphore = new struct semaphore; 18 22 if (!*semaphore) 19 23 return KERN_RESOURCE_SHORTAGE; 24 + 25 + (*semaphore)->sem = new Darling::FutexSemaphore(value); 20 26 21 - if (::sem_init(&(*semaphore)->sem, 0, value) == -1) 22 - { 23 - if (errno == EINVAL) 24 - return KERN_INVALID_ARGUMENT; 25 - else if (errno == ENOMEM) 26 - return KERN_RESOURCE_SHORTAGE; 27 - else 28 - return KERN_FAILURE; 29 - } 30 27 return KERN_SUCCESS; 31 28 } 32 29 ··· 38 35 if (!semaphore) 39 36 return KERN_INVALID_ARGUMENT; 40 37 41 - if (::sem_destroy(&semaphore->sem) == -1) 42 - return KERN_INVALID_ARGUMENT; 43 - 38 + delete semaphore->sem; 44 39 delete semaphore; 45 40 return KERN_SUCCESS; 46 41 } ··· 51 46 if (!semaphore) 52 47 return KERN_INVALID_ARGUMENT; 53 48 54 - if (::sem_post(&semaphore->sem) == -1) 55 - return KERN_INVALID_ARGUMENT; 49 + semaphore->sem->signal(); 56 50 57 51 return KERN_SUCCESS; 58 52 } 59 53 60 54 kern_return_t semaphore_signal_all(esemaphore_t semaphore) 61 55 { 62 - MACH_STUB(); 56 + TRACE1(semaphore); 57 + if (!semaphore) 58 + return KERN_INVALID_ARGUMENT; 59 + 60 + semaphore->sem->signalAll(); 61 + 62 + return KERN_SUCCESS; 63 63 } 64 64 65 65 kern_return_t semaphore_wait(esemaphore_t semaphore) ··· 67 67 TRACE1(semaphore); 68 68 if (!semaphore) 69 69 return KERN_INVALID_ARGUMENT; 70 + 71 + semaphore->sem->wait(); 70 72 71 - if (::sem_wait(&semaphore->sem) == -1) 72 - { 73 - if (errno == EINVAL) 74 - return KERN_INVALID_ARGUMENT; 75 - else if (errno == EDEADLK) 76 - return KERN_OPERATION_TIMED_OUT; // the closest we can get 77 - else 78 - return KERN_FAILURE; 79 - } 80 73 return KERN_SUCCESS; 81 74 } 82 75
+6 -1
src/libSystem/kernel-mach/semaphore.h
··· 4 4 #include "task.h" 5 5 #include <mach/kern_return.h> 6 6 7 + namespace Darling 8 + { 9 + class FutexSemaphore; 10 + } 11 + 7 12 struct semaphore 8 13 { 9 - sem_t sem; 14 + Darling::FutexSemaphore* sem; 10 15 }; 11 16 12 17 typedef semaphore* esemaphore_t;
+81
tests/src/mach_semaphore.c
··· 1 + // mach_semaphore.c 2 + 3 + #include <stdio.h> 4 + #include <unistd.h> 5 + #include <stdlib.h> 6 + #include <pthread.h> 7 + #include <mach/mach.h> 8 + 9 + #define OUT_ON_MACH_ERROR(msg, retval) \ 10 + if (kr != KERN_SUCCESS) { mach_error(msg ":" , kr); goto out; } 11 + 12 + #define PTHID() (unsigned long)(pthread_self()) 13 + 14 + #define SEMAPHORE_WAIT(s, n) \ 15 + { int i; for (i = 0; i < (n); i++) { semaphore_wait((s)); } } 16 + 17 + semaphore_t g_sem[2]; 18 + 19 + void * 20 + start_routine(void *id) 21 + { 22 + semaphore_signal(g_sem[1]); 23 + printf("thread: %lx about to decrement semaphore count\n", id); 24 + semaphore_wait(g_sem[0]); 25 + printf("thread: %lx succeeded in decrementing semaphore count\n", id); 26 + semaphore_signal(g_sem[1]); 27 + return (void *)0; 28 + } 29 + 30 + int 31 + main(void) 32 + { 33 + pthread_t pthread1, pthread2, pthread3; 34 + semaphore_t* sem = g_sem; 35 + kern_return_t kr; 36 + 37 + setbuf(stdout, NULL); 38 + 39 + kr = semaphore_create(mach_task_self(), &sem[0], SYNC_POLICY_FIFO, 0); 40 + OUT_ON_MACH_ERROR("semaphore_create", kr); 41 + 42 + kr = semaphore_create(mach_task_self(), &sem[1], SYNC_POLICY_FIFO, 0); 43 + OUT_ON_MACH_ERROR("semaphore_create", kr); 44 + 45 + (void)pthread_create(&pthread1, (const pthread_attr_t *)0, 46 + start_routine, (void *) 0); 47 + printf("created thread1=%lx\n", 0); 48 + 49 + (void)pthread_create(&pthread2, (const pthread_attr_t *)0, 50 + start_routine, (void *) 1); 51 + printf("created thread2=%lx\n", 1); 52 + 53 + (void)pthread_create(&pthread3, (const pthread_attr_t *)0, 54 + start_routine, (void *) 2); 55 + printf("created thread3=%lx\n", 2); 56 + 57 + // wait until all three threads are ready 58 + SEMAPHORE_WAIT(sem[1], 3); 59 + 60 + // printf("main: about to signal thread3\n"); 61 + // semaphore_signal_thread(sem[0], pthread_mach_thread_np(pthread3)); 62 + 63 + // wait for thread3 to sem_signal() 64 + // semaphore_wait(sem[1]); 65 + 66 + sleep(1); 67 + printf("main: about to signal all threads\n"); 68 + semaphore_signal_all(sem[0]); 69 + 70 + // wait for thread1 and thread2 to sem_signal() 71 + SEMAPHORE_WAIT(sem[1], 3); 72 + 73 + out: 74 + if (sem[0]) 75 + semaphore_destroy(mach_task_self(), sem[0]); 76 + if (sem[1]) 77 + semaphore_destroy(mach_task_self(), sem[1]); 78 + 79 + exit(kr); 80 + } 81 +