1 /* Copyright (C) 1999 Aladdin Enterprises. All rights reserved. 2 3 This software is provided AS-IS with no warranty, either express or 4 implied. 5 6 This software is distributed under license and may not be copied, 7 modified or distributed except as expressly authorized under the terms 8 of the license contained in the file LICENSE in this distribution. 9 10 For more information about licensing, please refer to 11 http://www.ghostscript.com/licensing/. For information on 12 commercial licensing, go to http://www.artifex.com/licensing/ or 13 contact Artifex Software, Inc., 101 Lucas Valley Road #110, 14 San Rafael, CA 94903, U.S.A., +1(415)492-9861. 15 */ 16 17 /* $Id: gp_wsync.c,v 1.4 2002/02/21 22:24:52 giles Exp $ */ 18 /* MS Windows (Win32) thread / semaphore / monitor implementation */ 19 /* original multi-threading code by John Desrosiers */ 20 #include "malloc_.h" 21 #include "gserror.h" 22 #include "gserrors.h" 23 #include "gpsync.h" 24 #include "windows_.h" 25 #include <process.h> 26 27 /* ------- Synchronization primitives -------- */ 28 29 /* Semaphore supports wait/signal semantics */ 30 31 typedef struct win32_semaphore_s { 32 HANDLE handle; /* returned from CreateSemaphore */ 33 } win32_semaphore; 34 35 uint 36 gp_semaphore_sizeof(void) 37 { 38 return sizeof(win32_semaphore); 39 } 40 41 int /* if sema <> 0 rets -ve error, 0 ok; if sema == 0, 0 movable, 1 fixed */ 42 gp_semaphore_open( 43 gp_semaphore * sema /* create semaphore here */ 44 ) 45 { 46 win32_semaphore *const winSema = (win32_semaphore *)sema; 47 48 if (winSema) { 49 winSema->handle = CreateSemaphore(NULL, 0, max_int, NULL); 50 return 51 (winSema->handle != NULL ? 0 : 52 gs_note_error(gs_error_unknownerror)); 53 } else 54 return 0; /* Win32 semaphores handles may be moved */ 55 } 56 57 int 58 gp_semaphore_close( 59 gp_semaphore * sema /* semaphore to affect */ 60 ) 61 { 62 win32_semaphore *const winSema = (win32_semaphore *)sema; 63 64 if (winSema->handle != NULL) 65 CloseHandle(winSema->handle); 66 winSema->handle = NULL; 67 return 0; 68 } 69 70 int /* rets 0 ok, -ve error */ 71 gp_semaphore_wait( 72 gp_semaphore * sema /* semaphore to affect */ 73 ) 74 { 75 win32_semaphore *const winSema = (win32_semaphore *)sema; 76 77 return 78 (WaitForSingleObject(winSema->handle, INFINITE) == WAIT_OBJECT_0 79 ? 0 : gs_error_unknownerror); 80 } 81 82 int /* rets 0 ok, -ve error */ 83 gp_semaphore_signal( 84 gp_semaphore * sema /* semaphore to affect */ 85 ) 86 { 87 win32_semaphore *const winSema = (win32_semaphore *)sema; 88 89 return 90 (ReleaseSemaphore(winSema->handle, 1, NULL) ? 0 : 91 gs_error_unknownerror); 92 } 93 94 95 /* Monitor supports enter/leave semantics */ 96 97 typedef struct win32_monitor_s { 98 CRITICAL_SECTION lock; /* critical section lock */ 99 } win32_monitor; 100 101 uint 102 gp_monitor_sizeof(void) 103 { 104 return sizeof(win32_monitor); 105 } 106 107 int /* if sema <> 0 rets -ve error, 0 ok; if sema == 0, 0 movable, 1 fixed */ 108 gp_monitor_open( 109 gp_monitor * mon /* create monitor here */ 110 ) 111 { 112 win32_monitor *const winMon = (win32_monitor *)mon; 113 114 if (mon) { 115 InitializeCriticalSection(&winMon->lock); /* returns no status */ 116 return 0; 117 } else 118 return 1; /* Win32 critical sections mutsn't be moved */ 119 } 120 121 int 122 gp_monitor_close( 123 gp_monitor * mon /* monitor to affect */ 124 ) 125 { 126 win32_monitor *const winMon = (win32_monitor *)mon; 127 128 DeleteCriticalSection(&winMon->lock); /* rets no status */ 129 return 0; 130 } 131 132 int /* rets 0 ok, -ve error */ 133 gp_monitor_enter( 134 gp_monitor * mon /* monitor to affect */ 135 ) 136 { 137 win32_monitor *const winMon = (win32_monitor *)mon; 138 139 EnterCriticalSection(&winMon->lock); /* rets no status */ 140 return 0; 141 } 142 143 int /* rets 0 ok, -ve error */ 144 gp_monitor_leave( 145 gp_monitor * mon /* monitor to affect */ 146 ) 147 { 148 win32_monitor *const winMon = (win32_monitor *)mon; 149 150 LeaveCriticalSection(&winMon->lock); /* rets no status */ 151 return 0; 152 } 153 154 /* --------- Thread primitives ---------- */ 155 156 typedef struct gp_thread_creation_closure_s { 157 gp_thread_creation_callback_t function; /* function to start */ 158 void *data; /* magic data to pass to thread */ 159 } gp_thread_creation_closure; 160 161 /* Origin of new threads started by gp_create_thread */ 162 private void 163 gp_thread_begin_wrapper( 164 void *thread_data /* gp_thread_creation_closure passed as magic data */ 165 ) 166 { 167 gp_thread_creation_closure closure; 168 169 closure = *(gp_thread_creation_closure *)thread_data; 170 free(thread_data); 171 (*closure.function)(closure.data); 172 _endthread(); 173 } 174 175 /* Call a function on a brand new thread */ 176 int /* 0 ok, -ve error */ 177 gp_create_thread( 178 gp_thread_creation_callback_t function, /* function to start */ 179 void *data /* magic data to pass to thread fn */ 180 ) 181 { 182 /* Create the magic closure that thread_wrapper gets passed */ 183 gp_thread_creation_closure *closure = 184 (gp_thread_creation_closure *)malloc(sizeof(*closure)); 185 186 if (!closure) 187 return gs_error_VMerror; 188 closure->function = function; 189 closure->data = data; 190 191 /* 192 * Start thread_wrapper. The Watcom _beginthread returns (int)(-1) if 193 * the call fails. The Microsoft _beginthread returns -1 (according to 194 * the doc, even though the return type is "unsigned long" !!!) if the 195 * call fails; we aren't sure what the Borland _beginthread returns. 196 * The hack with ~ avoids a source code commitment as to whether the 197 * return type is [u]int or [u]long. 198 * 199 * BEGIN_THREAD is a macro (defined in windows_.h) because _beginthread 200 * takes different arguments in Watcom C. 201 */ 202 if (~BEGIN_THREAD(gp_thread_begin_wrapper, 0, closure) != 0) 203 return 0; 204 return_error(gs_error_unknownerror); 205 } 206 207