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 Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2010 Red Hat, Inc.
9 This file is part of Cygwin.
11 This software is a copyrighted work licensed under the terms of the
12 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
16 #include "miscfuncs.h"
21 #undef WaitForSingleObject
23 muto NO_COPY lock_process::locker;
33 muto::init (const char *s)
35 char *already_exists = (char *) InterlockedExchangePointer (&name, s);
42 /* Create event which is used in the fallback case when blocking is necessary */
43 bruteforce = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
45 api_fatal ("couldn't allocate muto '%s', %E", s);
51 #if 0 /* FIXME: Do we need this? mutos aren't destroyed until process exit */
52 /* Destructor (racy?) */
58 HANDLE h = bruteforce;
60 /* Just need to close the event handle */
66 /* Acquire the lock. Argument is the number of milliseconds to wait for
67 the lock. Multiple visits from the same thread are allowed and should
70 Note: The goal here is to minimize, as much as possible, calls to the
71 OS. Hence the use of InterlockedIncrement, etc., rather than (much) more
72 expensive OS mutexes. */
74 muto::acquire (DWORD ms)
76 void *this_tls = &_my_tls;
80 /* Increment the waiters part of the class. Need to do this first to
81 avoid potential races. */
82 LONG was_waiting = ms ? InterlockedIncrement (&waiters) : 0;
84 while (was_waiting || InterlockedExchange (&sync, 1) != 0)
85 switch (WaitForSingleObject (bruteforce, ms))
91 return 0; /* failed. */
94 /* Have to do it this way to avoid a race */
96 InterlockedIncrement (&waiters);
98 tls = this_tls; /* register this thread. */
101 return ++visits; /* Increment visit count. */
107 return tls == &_my_tls;
110 /* Return the muto lock. Needs to be called once per every acquire. */
114 void *this_tls = &_my_tls;
116 if (tls != this_tls || !visits)
118 SetLastError (ERROR_NOT_OWNER); /* Didn't have the lock. */
119 return 0; /* failed. */
122 /* FIXME: Need to check that other thread has not exited, too. */
125 tls = 0; /* We were the last unlocker. */
126 InterlockedExchange (&sync, 0); /* Reset trigger. */
127 /* This thread had incremented waiters but had never decremented it.
128 Decrement it now. If it is >= 0 then there are possibly other
129 threads waiting for the lock, so trigger bruteforce. */
130 if (InterlockedDecrement (&waiters) >= 0)
131 SetEvent (bruteforce); /* Wake up one of the waiting threads */
132 else if (*name == '!')
134 CloseHandle (bruteforce); /* If *name == '!' and there are no
135 other waiters, then this is the
136 last time this muto will ever be
137 used, so close the handle. */
144 return 1; /* success. */