1 /* sync.cc: Synchronization functions for cygwin.
3 This file implements the methods for controlling the "muto" class
4 which is intended to operate similarly to a mutex but attempts to
5 avoid making expensive calls to the kernel.
7 This file is part of Cygwin.
9 This software is a copyrighted work licensed under the terms of the
10 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
14 #include "miscfuncs.h"
19 #undef WaitForSingleObject
21 muto NO_COPY
lock_process::locker
;
31 muto::init (const char *s
)
33 char *already_exists
= (char *) InterlockedExchangePointer ((PVOID
*) &name
,
41 /* Create event which is used in the fallback case when blocking is necessary */
42 bruteforce
= CreateEvent (&sec_none_nih
, FALSE
, FALSE
, NULL
);
44 api_fatal ("couldn't allocate muto '%s', %E", s
);
50 #if 0 /* FIXME: Do we need this? mutos aren't destroyed until process exit */
51 /* Destructor (racy?) */
57 HANDLE h
= bruteforce
;
59 /* Just need to close the event handle */
65 /* Acquire the lock. Argument is the number of milliseconds to wait for
66 the lock. Multiple visits from the same thread are allowed and should
69 Note: The goal here is to minimize, as much as possible, calls to the
70 OS. Hence the use of InterlockedIncrement, etc., rather than (much) more
71 expensive OS mutexes. */
73 muto::acquire (DWORD ms
)
75 void *this_tls
= &_my_tls
;
79 /* Increment the waiters part of the class. Need to do this first to
80 avoid potential races. */
81 LONG was_waiting
= ms
? InterlockedIncrement (&waiters
) : 0;
83 while (was_waiting
|| InterlockedExchange (&sync
, 1) != 0)
84 switch (WaitForSingleObject (bruteforce
, ms
))
90 return 0; /* failed. */
93 /* Have to do it this way to avoid a race */
95 InterlockedIncrement (&waiters
);
97 tls
= this_tls
; /* register this thread. */
100 return ++visits
; /* Increment visit count. */
106 return tls
== &_my_tls
;
109 /* Return the muto lock. Needs to be called once per every acquire. */
111 muto::release (_cygtls
*this_tls
)
113 if (tls
!= this_tls
|| !visits
)
115 SetLastError (ERROR_NOT_OWNER
); /* Didn't have the lock. */
116 return 0; /* failed. */
119 /* FIXME: Need to check that other thread has not exited, too. */
122 tls
= 0; /* We were the last unlocker. */
123 InterlockedExchange (&sync
, 0); /* Reset trigger. */
124 /* This thread had incremented waiters but had never decremented it.
125 Decrement it now. If it is >= 0 then there are possibly other
126 threads waiting for the lock, so trigger bruteforce. */
127 if (InterlockedDecrement (&waiters
) >= 0)
128 SetEvent (bruteforce
); /* Wake up one of the waiting threads */
129 else if (*name
== '!')
131 CloseHandle (bruteforce
); /* If *name == '!' and there are no
132 other waiters, then this is the
133 last time this muto will ever be
134 used, so close the handle. */
141 return 1; /* success. */