]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/sync.cc
* exceptions.cc (unused_sig_wrapper): Eliminate unused parameter to asm.
[newlib-cygwin.git] / winsup / cygwin / sync.cc
1 /* sync.cc: Synchronization functions for cygwin.
2
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.
6
7 Copyright 2000, 2001 Red Hat, Inc.
8
9 Written by Christopher Faylor <cgf@cygnus.com>
10
11 This file is part of Cygwin.
12
13 This software is a copyrighted work licensed under the terms of the
14 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
15 details. */
16
17 #include "winsup.h"
18 #include <stdlib.h>
19 #include <time.h>
20 #include <sys/wait.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include "sync.h"
24 #include "security.h"
25
26 muto NO_COPY muto_start;
27
28 #undef WaitForSingleObject
29
30 /* Constructor */
31 muto *
32 muto::init (int inh, const char *s)
33 {
34 waiters = -1;
35 /* Create event which is used in the fallback case when blocking is necessary */
36 if (!(bruteforce = CreateEvent (inh ? &sec_all_nih : &sec_none_nih, FALSE, FALSE, NULL)))
37 {
38 DWORD oerr = GetLastError ();
39 SetLastError (oerr);
40 return NULL;
41 }
42 name = s;
43 next = muto_start.next;
44 muto_start.next = this;
45 return this;
46 }
47
48 #if 0 /* FIXME: Do we need this? mutos aren't destroyed until process exit */
49 /* Destructor (racy?) */
50 muto::~muto ()
51 {
52 while (visits)
53 release ();
54
55 HANDLE h = bruteforce;
56 bruteforce = NULL;
57 /* Just need to close the event handle */
58 if (h)
59 CloseHandle (h);
60 }
61 #endif
62
63 /* Acquire the lock. Argument is the number of milliseconds to wait for
64 the lock. Multiple visits from the same thread are allowed and should
65 be handled correctly.
66
67 Note: The goal here is to minimize, as much as possible, calls to the
68 OS. Hence the use of InterlockedIncrement, etc., rather than (much) more
69 expensive OS mutexes. */
70 int
71 muto::acquire (DWORD ms)
72 {
73 DWORD this_tid = GetCurrentThreadId ();
74
75 if (tid != this_tid)
76 {
77 /* Increment the waiters part of the class. Need to do this first to
78 avoid potential races. */
79 LONG was_waiting = InterlockedIncrement (&waiters);
80
81 /* This is deceptively simple. Basically, it allows multiple attempts to
82 lock the same muto to succeed without attempting to manipulate sync.
83 If the muto is already locked then this thread will wait for ms until
84 it is signalled by muto::release. Then it will attempt to grab the
85 sync field. If it succeeds, then this thread owns the muto.
86
87 There is a pathological condition where a thread times out waiting for
88 bruteforce but the release code triggers the bruteforce event. In this
89 case, it is possible for a thread which is going to wait for bruteforce
90 to wake up immediately. It will then attempt to grab sync but will fail
91 and go back to waiting. */
92 if (tid != this_tid && (was_waiting || InterlockedExchange (&sync, 1) != 0))
93 {
94 switch (WaitForSingleObject (bruteforce, ms))
95 {
96 case WAIT_OBJECT_0:
97 goto gotit;
98 break;
99 default:
100 InterlockedDecrement (&waiters);
101 return 0; /* failed. */
102 }
103 }
104 }
105
106 gotit:
107 tid = this_tid; /* register this thread. */
108 return ++visits; /* Increment visit count. */
109 }
110
111 /* Return the muto lock. Needs to be called once per every acquire. */
112 int
113 muto::release ()
114 {
115 DWORD this_tid = GetCurrentThreadId ();
116
117 if (tid != this_tid || !visits)
118 {
119 SetLastError (ERROR_NOT_OWNER); /* Didn't have the lock. */
120 return 0; /* failed. */
121 }
122
123 /* FIXME: Need to check that other thread has not exited, too. */
124 if (!--visits)
125 {
126 tid = 0; /* We were the last unlocker. */
127 (void) InterlockedExchange (&sync, 0); /* Reset trigger. */
128 /* This thread had incremented waiters but had never decremented it.
129 Decrement it now. If it is >= 0 then there are possibly other
130 threads waiting for the lock, so trigger bruteforce. */
131 if (InterlockedDecrement (&waiters) >= 0)
132 (void) SetEvent (bruteforce); /* Wake up one of the waiting threads */
133 }
134
135 return 1; /* success. */
136 }
137
138 /* Call only when we're exiting. This is not thread safe. */
139 void
140 muto::reset ()
141 {
142 visits = sync = tid = 0;
143 InterlockedExchange (&waiters, -1);
144 if (bruteforce)
145 {
146 CloseHandle (bruteforce);
147 bruteforce = CreateEvent (&sec_none_nih, FALSE, FALSE, name);
148 }
149 }
This page took 0.045108 seconds and 6 git commands to generate.