| /* |
| * Win32 semaphores |
| * |
| * Copyright 1998 Alexandre Julliard |
| */ |
| |
| #include <assert.h> |
| #include "windows.h" |
| #include "winerror.h" |
| #include "k32obj.h" |
| #include "process.h" |
| #include "thread.h" |
| #include "heap.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 ) |
| { |
| HANDLE32 handle; |
| SEMAPHORE *sem; |
| |
| /* Check parameters */ |
| |
| if ((max <= 0) || (initial < 0) || (initial > max)) |
| { |
| SetLastError( ERROR_INVALID_PARAMETER ); |
| return INVALID_HANDLE_VALUE32; |
| } |
| |
| SYSTEM_LOCK(); |
| sem = (SEMAPHORE *)K32OBJ_Create( K32OBJ_SEMAPHORE, sizeof(*sem), |
| name, 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 ); |
| 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 ) |
| { |
| SEMAPHORE *sem; |
| |
| SYSTEM_LOCK(); |
| if (!(sem = (SEMAPHORE *)HANDLE_GetObjPtr( PROCESS_Current(), handle, |
| K32OBJ_SEMAPHORE, |
| SEMAPHORE_MODIFY_STATE ))) |
| { |
| SYSTEM_UNLOCK(); |
| return FALSE; |
| } |
| 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 ); |
| } |