xref: /plan9/sys/src/cmd/gs/src/gp_wsync.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1999 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gp_wsync.c,v 1.4 2002/02/21 22:24:52 giles Exp $ */
187dd7cddfSDavid du Colombier /* MS Windows (Win32) thread / semaphore / monitor implementation */
197dd7cddfSDavid du Colombier /* original multi-threading code by John Desrosiers */
207dd7cddfSDavid du Colombier #include "malloc_.h"
217dd7cddfSDavid du Colombier #include "gserror.h"
227dd7cddfSDavid du Colombier #include "gserrors.h"
237dd7cddfSDavid du Colombier #include "gpsync.h"
247dd7cddfSDavid du Colombier #include "windows_.h"
257dd7cddfSDavid du Colombier #include <process.h>
267dd7cddfSDavid du Colombier 
277dd7cddfSDavid du Colombier /* ------- Synchronization primitives -------- */
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier /* Semaphore supports wait/signal semantics */
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier typedef struct win32_semaphore_s {
327dd7cddfSDavid du Colombier     HANDLE handle;		/* returned from CreateSemaphore */
337dd7cddfSDavid du Colombier } win32_semaphore;
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier uint
gp_semaphore_sizeof(void)367dd7cddfSDavid du Colombier gp_semaphore_sizeof(void)
377dd7cddfSDavid du Colombier {
387dd7cddfSDavid du Colombier     return sizeof(win32_semaphore);
397dd7cddfSDavid du Colombier }
407dd7cddfSDavid du Colombier 
417dd7cddfSDavid du Colombier int	/* if sema <> 0 rets -ve error, 0 ok; if sema == 0, 0 movable, 1 fixed */
gp_semaphore_open(gp_semaphore * sema)427dd7cddfSDavid du Colombier gp_semaphore_open(
437dd7cddfSDavid du Colombier 		  gp_semaphore * sema	/* create semaphore here */
447dd7cddfSDavid du Colombier )
457dd7cddfSDavid du Colombier {
467dd7cddfSDavid du Colombier     win32_semaphore *const winSema = (win32_semaphore *)sema;
477dd7cddfSDavid du Colombier 
487dd7cddfSDavid du Colombier     if (winSema) {
497dd7cddfSDavid du Colombier 	winSema->handle = CreateSemaphore(NULL, 0, max_int, NULL);
507dd7cddfSDavid du Colombier 	return
517dd7cddfSDavid du Colombier 	    (winSema->handle != NULL ? 0 :
527dd7cddfSDavid du Colombier 	     gs_note_error(gs_error_unknownerror));
537dd7cddfSDavid du Colombier     } else
547dd7cddfSDavid du Colombier 	return 0;		/* Win32 semaphores handles may be moved */
557dd7cddfSDavid du Colombier }
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier int
gp_semaphore_close(gp_semaphore * sema)587dd7cddfSDavid du Colombier gp_semaphore_close(
597dd7cddfSDavid du Colombier 		   gp_semaphore * sema	/* semaphore to affect */
607dd7cddfSDavid du Colombier )
617dd7cddfSDavid du Colombier {
627dd7cddfSDavid du Colombier     win32_semaphore *const winSema = (win32_semaphore *)sema;
637dd7cddfSDavid du Colombier 
647dd7cddfSDavid du Colombier     if (winSema->handle != NULL)
657dd7cddfSDavid du Colombier 	CloseHandle(winSema->handle);
667dd7cddfSDavid du Colombier     winSema->handle = NULL;
677dd7cddfSDavid du Colombier     return 0;
687dd7cddfSDavid du Colombier }
697dd7cddfSDavid du Colombier 
707dd7cddfSDavid du Colombier int				/* rets 0 ok, -ve error */
gp_semaphore_wait(gp_semaphore * sema)717dd7cddfSDavid du Colombier gp_semaphore_wait(
727dd7cddfSDavid du Colombier 		  gp_semaphore * sema	/* semaphore to affect */
737dd7cddfSDavid du Colombier )
747dd7cddfSDavid du Colombier {
757dd7cddfSDavid du Colombier     win32_semaphore *const winSema = (win32_semaphore *)sema;
767dd7cddfSDavid du Colombier 
777dd7cddfSDavid du Colombier     return
787dd7cddfSDavid du Colombier 	(WaitForSingleObject(winSema->handle, INFINITE) == WAIT_OBJECT_0
797dd7cddfSDavid du Colombier 	 ? 0 : gs_error_unknownerror);
807dd7cddfSDavid du Colombier }
817dd7cddfSDavid du Colombier 
827dd7cddfSDavid du Colombier int				/* rets 0 ok, -ve error */
gp_semaphore_signal(gp_semaphore * sema)837dd7cddfSDavid du Colombier gp_semaphore_signal(
847dd7cddfSDavid du Colombier 		    gp_semaphore * sema	/* semaphore to affect */
857dd7cddfSDavid du Colombier )
867dd7cddfSDavid du Colombier {
877dd7cddfSDavid du Colombier     win32_semaphore *const winSema = (win32_semaphore *)sema;
887dd7cddfSDavid du Colombier 
897dd7cddfSDavid du Colombier     return
907dd7cddfSDavid du Colombier 	(ReleaseSemaphore(winSema->handle, 1, NULL) ? 0 :
917dd7cddfSDavid du Colombier 	 gs_error_unknownerror);
927dd7cddfSDavid du Colombier }
937dd7cddfSDavid du Colombier 
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier /* Monitor supports enter/leave semantics */
967dd7cddfSDavid du Colombier 
977dd7cddfSDavid du Colombier typedef struct win32_monitor_s {
987dd7cddfSDavid du Colombier     CRITICAL_SECTION lock;	/* critical section lock */
997dd7cddfSDavid du Colombier } win32_monitor;
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier uint
gp_monitor_sizeof(void)1027dd7cddfSDavid du Colombier gp_monitor_sizeof(void)
1037dd7cddfSDavid du Colombier {
1047dd7cddfSDavid du Colombier     return sizeof(win32_monitor);
1057dd7cddfSDavid du Colombier }
1067dd7cddfSDavid du Colombier 
1077dd7cddfSDavid du Colombier int	/* if sema <> 0 rets -ve error, 0 ok; if sema == 0, 0 movable, 1 fixed */
gp_monitor_open(gp_monitor * mon)1087dd7cddfSDavid du Colombier gp_monitor_open(
1097dd7cddfSDavid du Colombier 		gp_monitor * mon	/* create monitor here */
1107dd7cddfSDavid du Colombier )
1117dd7cddfSDavid du Colombier {
1127dd7cddfSDavid du Colombier     win32_monitor *const winMon = (win32_monitor *)mon;
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier     if (mon) {
1157dd7cddfSDavid du Colombier 	InitializeCriticalSection(&winMon->lock);	/* returns no status */
1167dd7cddfSDavid du Colombier 	return 0;
1177dd7cddfSDavid du Colombier     } else
1187dd7cddfSDavid du Colombier 	return 1;		/* Win32 critical sections mutsn't be moved */
1197dd7cddfSDavid du Colombier }
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier int
gp_monitor_close(gp_monitor * mon)1227dd7cddfSDavid du Colombier gp_monitor_close(
1237dd7cddfSDavid du Colombier 		 gp_monitor * mon	/* monitor to affect */
1247dd7cddfSDavid du Colombier )
1257dd7cddfSDavid du Colombier {
1267dd7cddfSDavid du Colombier     win32_monitor *const winMon = (win32_monitor *)mon;
1277dd7cddfSDavid du Colombier 
1287dd7cddfSDavid du Colombier     DeleteCriticalSection(&winMon->lock);	/* rets no status */
1297dd7cddfSDavid du Colombier     return 0;
1307dd7cddfSDavid du Colombier }
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier int				/* rets 0 ok, -ve error */
gp_monitor_enter(gp_monitor * mon)1337dd7cddfSDavid du Colombier gp_monitor_enter(
1347dd7cddfSDavid du Colombier 		 gp_monitor * mon	/* monitor to affect */
1357dd7cddfSDavid du Colombier )
1367dd7cddfSDavid du Colombier {
1377dd7cddfSDavid du Colombier     win32_monitor *const winMon = (win32_monitor *)mon;
1387dd7cddfSDavid du Colombier 
1397dd7cddfSDavid du Colombier     EnterCriticalSection(&winMon->lock);	/* rets no status */
1407dd7cddfSDavid du Colombier     return 0;
1417dd7cddfSDavid du Colombier }
1427dd7cddfSDavid du Colombier 
1437dd7cddfSDavid du Colombier int				/* rets 0 ok, -ve error */
gp_monitor_leave(gp_monitor * mon)1447dd7cddfSDavid du Colombier gp_monitor_leave(
1457dd7cddfSDavid du Colombier 		 gp_monitor * mon	/* monitor to affect */
1467dd7cddfSDavid du Colombier )
1477dd7cddfSDavid du Colombier {
1487dd7cddfSDavid du Colombier     win32_monitor *const winMon = (win32_monitor *)mon;
1497dd7cddfSDavid du Colombier 
1507dd7cddfSDavid du Colombier     LeaveCriticalSection(&winMon->lock);	/* rets no status */
1517dd7cddfSDavid du Colombier     return 0;
1527dd7cddfSDavid du Colombier }
1537dd7cddfSDavid du Colombier 
1547dd7cddfSDavid du Colombier /* --------- Thread primitives ---------- */
1557dd7cddfSDavid du Colombier 
1567dd7cddfSDavid du Colombier typedef struct gp_thread_creation_closure_s {
1577dd7cddfSDavid du Colombier     gp_thread_creation_callback_t function;	/* function to start */
1587dd7cddfSDavid du Colombier     void *data;			/* magic data to pass to thread */
1597dd7cddfSDavid du Colombier } gp_thread_creation_closure;
1607dd7cddfSDavid du Colombier 
1617dd7cddfSDavid du Colombier /* Origin of new threads started by gp_create_thread */
1627dd7cddfSDavid du Colombier private void
gp_thread_begin_wrapper(void * thread_data)1637dd7cddfSDavid du Colombier gp_thread_begin_wrapper(
1647dd7cddfSDavid du Colombier 			void *thread_data	/* gp_thread_creation_closure passed as magic data */
1657dd7cddfSDavid du Colombier )
1667dd7cddfSDavid du Colombier {
1677dd7cddfSDavid du Colombier     gp_thread_creation_closure closure;
1687dd7cddfSDavid du Colombier 
1697dd7cddfSDavid du Colombier     closure = *(gp_thread_creation_closure *)thread_data;
1707dd7cddfSDavid du Colombier     free(thread_data);
1717dd7cddfSDavid du Colombier     (*closure.function)(closure.data);
1727dd7cddfSDavid du Colombier     _endthread();
1737dd7cddfSDavid du Colombier }
1747dd7cddfSDavid du Colombier 
1757dd7cddfSDavid du Colombier /* Call a function on a brand new thread */
1767dd7cddfSDavid du Colombier int				/* 0 ok, -ve error */
gp_create_thread(gp_thread_creation_callback_t function,void * data)1777dd7cddfSDavid du Colombier gp_create_thread(
1787dd7cddfSDavid du Colombier 		 gp_thread_creation_callback_t function,	/* function to start */
1797dd7cddfSDavid du Colombier 		 void *data	/* magic data to pass to thread fn */
1807dd7cddfSDavid du Colombier )
1817dd7cddfSDavid du Colombier {
1827dd7cddfSDavid du Colombier     /* Create the magic closure that thread_wrapper gets passed */
1837dd7cddfSDavid du Colombier     gp_thread_creation_closure *closure =
1847dd7cddfSDavid du Colombier 	(gp_thread_creation_closure *)malloc(sizeof(*closure));
1857dd7cddfSDavid du Colombier 
1867dd7cddfSDavid du Colombier     if (!closure)
1877dd7cddfSDavid du Colombier 	return gs_error_VMerror;
1887dd7cddfSDavid du Colombier     closure->function = function;
1897dd7cddfSDavid du Colombier     closure->data = data;
1907dd7cddfSDavid du Colombier 
1917dd7cddfSDavid du Colombier     /*
1927dd7cddfSDavid du Colombier      * Start thread_wrapper.  The Watcom _beginthread returns (int)(-1) if
1937dd7cddfSDavid du Colombier      * the call fails.  The Microsoft _beginthread returns -1 (according to
1947dd7cddfSDavid du Colombier      * the doc, even though the return type is "unsigned long" !!!) if the
1957dd7cddfSDavid du Colombier      * call fails; we aren't sure what the Borland _beginthread returns.
1967dd7cddfSDavid du Colombier      * The hack with ~ avoids a source code commitment as to whether the
1977dd7cddfSDavid du Colombier      * return type is [u]int or [u]long.
1987dd7cddfSDavid du Colombier      *
1997dd7cddfSDavid du Colombier      * BEGIN_THREAD is a macro (defined in windows_.h) because _beginthread
2007dd7cddfSDavid du Colombier      * takes different arguments in Watcom C.
2017dd7cddfSDavid du Colombier      */
2027dd7cddfSDavid du Colombier     if (~BEGIN_THREAD(gp_thread_begin_wrapper, 0, closure) != 0)
2037dd7cddfSDavid du Colombier 	return 0;
2047dd7cddfSDavid du Colombier     return_error(gs_error_unknownerror);
2057dd7cddfSDavid du Colombier }
2067dd7cddfSDavid du Colombier 
207