/* * Win32 semaphores * * Copyright 1998 Alexandre Julliard */ #include #include "windows.h" #include "winerror.h" #include "k32obj.h" #include "process.h" #include "thread.h" #include "heap.h" #include "server/request.h" #include "server.h" typedef struct { K32OBJ header; THREAD_QUEUE wait_queue; LONG count; LONG max; } SEMAPHORE; static BOOL32 SEMAPHORE_Signaled( K32OBJ *obj, DWORD thread_id ); static BOOL32 SEMAPHORE_Satisfied( K32OBJ *obj, DWORD thread_id ); static void SEMAPHORE_AddWait( K32OBJ *obj, DWORD thread_id ); static void SEMAPHORE_RemoveWait( K32OBJ *obj, DWORD thread_id ); static void SEMAPHORE_Destroy( K32OBJ *obj ); const K32OBJ_OPS SEMAPHORE_Ops = { SEMAPHORE_Signaled, /* signaled */ SEMAPHORE_Satisfied, /* satisfied */ SEMAPHORE_AddWait, /* add_wait */ SEMAPHORE_RemoveWait, /* remove_wait */ NULL, /* read */ NULL, /* write */ SEMAPHORE_Destroy /* destroy */ }; /*********************************************************************** * CreateSemaphore32A (KERNEL32.174) */ HANDLE32 WINAPI CreateSemaphore32A( SECURITY_ATTRIBUTES *sa, LONG initial, LONG max, LPCSTR name ) { struct create_semaphore_request req; struct create_semaphore_reply reply; int len = name ? strlen(name) + 1 : 0; HANDLE32 handle; SEMAPHORE *sem; /* Check parameters */ if ((max <= 0) || (initial < 0) || (initial > max)) { SetLastError( ERROR_INVALID_PARAMETER ); return INVALID_HANDLE_VALUE32; } req.initial = (unsigned int)initial; req.max = (unsigned int)max; req.inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle); CLIENT_SendRequest( REQ_CREATE_SEMAPHORE, -1, 2, &req, sizeof(req), name, len ); CLIENT_WaitReply( &len, NULL, 1, &reply, sizeof(reply) ); CHECK_LEN( len, sizeof(reply) ); if (reply.handle == -1) return NULL; SYSTEM_LOCK(); sem = (SEMAPHORE *)K32OBJ_Create( K32OBJ_SEMAPHORE, sizeof(*sem), name, reply.handle, SEMAPHORE_ALL_ACCESS, sa, &handle); if (sem) { /* Finish initializing it */ sem->wait_queue = NULL; sem->count = initial; sem->max = max; K32OBJ_DecCount( &sem->header ); } SYSTEM_UNLOCK(); return handle; } /*********************************************************************** * CreateSemaphore32W (KERNEL32.175) */ HANDLE32 WINAPI CreateSemaphore32W( SECURITY_ATTRIBUTES *sa, LONG initial, LONG max, LPCWSTR name ) { LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name ); HANDLE32 ret = CreateSemaphore32A( sa, initial, max, nameA ); if (nameA) HeapFree( GetProcessHeap(), 0, nameA ); return ret; } /*********************************************************************** * OpenSemaphore32A (KERNEL32.545) */ HANDLE32 WINAPI OpenSemaphore32A( DWORD access, BOOL32 inherit, LPCSTR name ) { HANDLE32 handle = 0; K32OBJ *obj; SYSTEM_LOCK(); if ((obj = K32OBJ_FindNameType( name, K32OBJ_SEMAPHORE )) != NULL) { handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit, -1 ); K32OBJ_DecCount( obj ); } SYSTEM_UNLOCK(); return handle; } /*********************************************************************** * OpenSemaphore32W (KERNEL32.546) */ HANDLE32 WINAPI OpenSemaphore32W( DWORD access, BOOL32 inherit, LPCWSTR name ) { LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name ); HANDLE32 ret = OpenSemaphore32A( access, inherit, nameA ); if (nameA) HeapFree( GetProcessHeap(), 0, nameA ); return ret; } /*********************************************************************** * ReleaseSemaphore (KERNEL32.583) */ BOOL32 WINAPI ReleaseSemaphore( HANDLE32 handle, LONG count, LONG *previous ) { struct release_semaphore_request req; SEMAPHORE *sem; if (count < 0) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } SYSTEM_LOCK(); if (!(sem = (SEMAPHORE *)HANDLE_GetObjPtr( PROCESS_Current(), handle, K32OBJ_SEMAPHORE, SEMAPHORE_MODIFY_STATE, &req.handle ))) { SYSTEM_UNLOCK(); return FALSE; } if (req.handle != -1) { struct release_semaphore_reply reply; int len; SYSTEM_UNLOCK(); req.count = (unsigned int)count; CLIENT_SendRequest( REQ_RELEASE_SEMAPHORE, -1, 1, &req, sizeof(req) ); if (CLIENT_WaitReply( &len, NULL, 1, &reply, sizeof(reply) )) return FALSE; CHECK_LEN( len, sizeof(reply) ); if (previous) *previous = reply.prev_count; return TRUE; } if (previous) *previous = sem->count; if (sem->count + count > sem->max) { SYSTEM_UNLOCK(); SetLastError( ERROR_TOO_MANY_POSTS ); return FALSE; } if (sem->count > 0) { /* There cannot be any thread waiting if the count is > 0 */ assert( sem->wait_queue == NULL ); sem->count += count; } else { sem->count = count; SYNC_WakeUp( &sem->wait_queue, count ); } K32OBJ_DecCount( &sem->header ); SYSTEM_UNLOCK(); return TRUE; } /*********************************************************************** * SEMAPHORE_Signaled */ static BOOL32 SEMAPHORE_Signaled( K32OBJ *obj, DWORD thread_id ) { SEMAPHORE *sem = (SEMAPHORE *)obj; assert( obj->type == K32OBJ_SEMAPHORE ); return (sem->count > 0); } /*********************************************************************** * SEMAPHORE_Satisfied * * Wait on this object has been satisfied. */ static BOOL32 SEMAPHORE_Satisfied( K32OBJ *obj, DWORD thread_id ) { SEMAPHORE *sem = (SEMAPHORE *)obj; assert( obj->type == K32OBJ_SEMAPHORE ); assert( sem->count > 0 ); sem->count--; return FALSE; /* Not abandoned */ } /*********************************************************************** * SEMAPHORE_AddWait * * Add current thread to object wait queue. */ static void SEMAPHORE_AddWait( K32OBJ *obj, DWORD thread_id ) { SEMAPHORE *sem = (SEMAPHORE *)obj; assert( obj->type == K32OBJ_SEMAPHORE ); THREAD_AddQueue( &sem->wait_queue, THREAD_ID_TO_THDB(thread_id) ); } /*********************************************************************** * SEMAPHORE_RemoveWait * * Remove thread from object wait queue. */ static void SEMAPHORE_RemoveWait( K32OBJ *obj, DWORD thread_id ) { SEMAPHORE *sem = (SEMAPHORE *)obj; assert( obj->type == K32OBJ_SEMAPHORE ); THREAD_RemoveQueue( &sem->wait_queue, THREAD_ID_TO_THDB(thread_id) ); } /*********************************************************************** * SEMAPHORE_Destroy */ static void SEMAPHORE_Destroy( K32OBJ *obj ) { SEMAPHORE *sem = (SEMAPHORE *)obj; assert( obj->type == K32OBJ_SEMAPHORE ); /* There cannot be any thread on the list since the ref count is 0 */ assert( sem->wait_queue == NULL ); obj->type = K32OBJ_UNKNOWN; HeapFree( SystemHeap, 0, sem ); }