diff options
Diffstat (limited to 'src/unix.c')
| -rw-r--r-- | src/unix.c | 144 |
1 files changed, 65 insertions, 79 deletions
@@ -27,8 +27,6 @@ Revision History: #include <sys/time.h> #include <sys/mman.h> #include <sys/select.h> -#include <sys/ipc.h> -#include <sys/sem.h> #include <pthread.h> #include <signal.h> #include <errno.h> @@ -1020,44 +1018,54 @@ SystemReleaseLock(ULONG u) } +/* + * These "semaphores" only ever signal between threads of this same + * process (see input.c's producer/consumer wait between the stdin + * reader thread and the command-dispatch thread) -- there is no + * cross-process handoff here, despite the SysV-semaphore-shaped API. + * A SysV semget(IPC_PRIVATE, ...) set is kernel-global, outlives the + * process, and only gets torn down by an explicit IPC_RMID -- so a + * killed (rather than gracefully quit()'d) process leaks it, and on a + * shared box with a low kern.ipc.semmni it doesn't take many leaked + * engines to exhaust the system-wide semaphore-set table. Every + * subsequent semget() then fails, and _WaitUntilTheresInputToRead + * (input.c) silently falls back to 100ms-polling instead of blocking + * on a real wait -- a ~1000x slowdown that looks exactly like machine + * contention. A pthread_mutex_t/pthread_cond_t pair does the same + * counting-semaphore job entirely in-process, with no kernel-persistent + * object to leak: the OS reclaims it unconditionally the instant the + * process dies, SIGKILL or not. + */ #define MAX_SEM (8) -int g_rgSemaphores[MAX_SEM]; -#ifdef DEBUG -ULONG g_rgSemValues[MAX_SEM]; -#endif + +typedef struct _SEM_ENTRY +{ + FLAG fInUse; + ULONG uCount; + pthread_mutex_t lock; + pthread_cond_t cond; +} +SEM_ENTRY; + +SEM_ENTRY g_rgSemaphores[MAX_SEM]; ULONG -SystemCreateSemaphore(ULONG uValue) +SystemCreateSemaphore(ULONG uValue) { ULONG u; - union semun { - int val; - struct semid_ds *buf; - unsigned short *array; - } value; if (uValue > MAX_USHORT) return((ULONG)-1); LOCK_SYSTEM; - for (u = 0; u < MAX_SEM; u++) + for (u = 0; u < MAX_SEM; u++) { - if (g_rgSemaphores[u] < 0) + if (g_rgSemaphores[u].fInUse == FALSE) { - g_rgSemaphores[u] = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600); - if (g_rgSemaphores[u] < 0) - { - u = (ULONG)-1; - goto end; - } - value.val = uValue; - if (semctl(g_rgSemaphores[u], 0, SETVAL, value) < 0) - { - (void)SystemDeleteSemaphore(u); - u = (ULONG)-1; - goto end; - } + pthread_mutex_init(&(g_rgSemaphores[u].lock), NULL); + pthread_cond_init(&(g_rgSemaphores[u].cond), NULL); + g_rgSemaphores[u].uCount = uValue; + g_rgSemaphores[u].fInUse = TRUE; #ifdef DEBUG - g_rgSemValues[u] = uValue; - Trace("Semaphore #%u created, initial value is %u\n", + Trace("Semaphore #%u created, initial value is %u\n", u, uValue); #endif goto end; @@ -1071,82 +1079,60 @@ SystemCreateSemaphore(ULONG uValue) FLAG SystemDeleteSemaphore(ULONG u) { - union semun { - int val; - struct semid_ds *buf; - unsigned short *array; - } value; FLAG fRet = TRUE; - memset(&value, 0, sizeof(value)); LOCK_SYSTEM; - if ((u < MAX_SEM) && (g_rgSemaphores[u] >= 0)) + if ((u < MAX_SEM) && (g_rgSemaphores[u].fInUse == TRUE)) { - if (semctl(g_rgSemaphores[u], 0, IPC_RMID, value) < 0) - { - fRet = FALSE; - } - else - { - g_rgSemaphores[u] = -1; - } + pthread_mutex_destroy(&(g_rgSemaphores[u].lock)); + pthread_cond_destroy(&(g_rgSemaphores[u].cond)); + g_rgSemaphores[u].fInUse = FALSE; + } + else + { + fRet = FALSE; } UNLOCK_SYSTEM; return(fRet); } void -SystemReleaseSemaphoreResource(ULONG u) +SystemReleaseSemaphoreResource(ULONG u) { - struct sembuf operation; - LOCK_SYSTEM; - if ((u < MAX_SEM) && (g_rgSemaphores[u] >= 0)) + if ((u < MAX_SEM) && (g_rgSemaphores[u].fInUse == TRUE)) { - operation.sem_num = u; - operation.sem_op = +1; - operation.sem_flg = 0; - if (semop(g_rgSemaphores[u], &operation, 1) < 0) - { - UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE, - NULL, "semop", (void *)errno, (void *)0, - __FILE__, __LINE__); - } + pthread_mutex_lock(&(g_rgSemaphores[u].lock)); + g_rgSemaphores[u].uCount += 1; #ifdef DEBUG - g_rgSemValues[u] += 1; - Trace("Semaphore #%u value incremented to %u\n", u, - g_rgSemValues[u]); + Trace("Semaphore #%u value incremented to %u\n", u, + g_rgSemaphores[u].uCount); #endif + pthread_cond_signal(&(g_rgSemaphores[u].cond)); + pthread_mutex_unlock(&(g_rgSemaphores[u].lock)); } UNLOCK_SYSTEM; } void -SystemObtainSemaphoreResource(ULONG u) +SystemObtainSemaphoreResource(ULONG u) { - struct sembuf operation; - LOCK_SYSTEM; - if ((u < MAX_SEM) && (g_rgSemaphores[u] >= 0)) + if ((u < MAX_SEM) && (g_rgSemaphores[u].fInUse == TRUE)) { - operation.sem_num = u; - operation.sem_op = -1; - operation.sem_flg = 0; + pthread_mutex_lock(&(g_rgSemaphores[u].lock)); UNLOCK_SYSTEM; - if (semop(g_rgSemaphores[u], &operation, 1) < 0) + while (g_rgSemaphores[u].uCount == 0) { - UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE, - NULL, "semop", (void *)errno, (void *)1, - __FILE__, __LINE__); + pthread_cond_wait(&(g_rgSemaphores[u].cond), + &(g_rgSemaphores[u].lock)); } + g_rgSemaphores[u].uCount -= 1; #ifdef DEBUG - if (g_rgSemValues[u] > 0) - { - g_rgSemValues[u] -= 1; - Trace("Semaphore #%u value decremented to %u\n", u, - g_rgSemValues[u]); - } + Trace("Semaphore #%u value decremented to %u\n", u, + g_rgSemaphores[u].uCount); #endif + pthread_mutex_unlock(&(g_rgSemaphores[u].lock)); return; } UNLOCK_SYSTEM; @@ -1187,9 +1173,9 @@ Return value: memset(g_AllocHash, 0, sizeof(g_AllocHash)); #endif - for (u = 0; u < MAX_SEM; u++) + for (u = 0; u < MAX_SEM; u++) { - g_rgSemaphores[u] = -1; + g_rgSemaphores[u].fInUse = FALSE; } InitializeListHead(&g_SystemThreadList); pthread_mutex_init(&g_SystemLock, NULL); |
