Cygwin: add newgrp release notes
[newlib-cygwin.git] / winsup / cygwin / sync.cc
blob7decb7d19871176de7bbfb593c28cf6f99f1195b
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
11 details. */
13 #include "winsup.h"
14 #include "miscfuncs.h"
15 #include "sync.h"
16 #include "thread.h"
17 #include "cygtls.h"
19 #undef WaitForSingleObject
21 muto NO_COPY lock_process::locker;
23 void
24 muto::grab ()
26 tls = &_my_tls;
29 /* Constructor */
30 muto *
31 muto::init (const char *s)
33 char *already_exists = (char *) InterlockedExchangePointer ((PVOID *) &name,
34 (PVOID) s);
35 if (already_exists)
36 while (!bruteforce)
37 yield ();
38 else
40 waiters = -1;
41 /* Create event which is used in the fallback case when blocking is necessary */
42 bruteforce = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
43 if (!bruteforce)
44 api_fatal ("couldn't allocate muto '%s', %E", s);
47 return this;
50 #if 0 /* FIXME: Do we need this? mutos aren't destroyed until process exit */
51 /* Destructor (racy?) */
52 muto::~muto ()
54 while (visits)
55 release ();
57 HANDLE h = bruteforce;
58 bruteforce = NULL;
59 /* Just need to close the event handle */
60 if (h)
61 CloseHandle (h);
63 #endif
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
67 be handled correctly.
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. */
72 int
73 muto::acquire (DWORD ms)
75 void *this_tls = &_my_tls;
77 if (tls != this_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))
86 case WAIT_OBJECT_0:
87 was_waiting = 0;
88 break;
89 default:
90 return 0; /* failed. */
93 /* Have to do it this way to avoid a race */
94 if (!ms)
95 InterlockedIncrement (&waiters);
97 tls = this_tls; /* register this thread. */
100 return ++visits; /* Increment visit count. */
103 bool
104 muto::acquired ()
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. */
120 if (!--visits)
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. */
135 #ifdef DEBUGGING
136 bruteforce = NULL;
137 #endif
141 return 1; /* success. */