]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/sync.cc
Rename _threadinfo to _cygtls, throughout.
[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, 2002, 2003, 2004 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 #undef WaitForSingleObject
27
28 DWORD NO_COPY muto::exiting_thread;
29
30 /* Constructor */
31 muto *
32 muto::init (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 (&sec_none_nih, FALSE, FALSE, NULL)))
37 {
38 DWORD oerr = GetLastError ();
39 SetLastError (oerr);
40 return NULL;
41 }
42 name = s;
43 return this;
44 }
45
46 #if 0 /* FIXME: Do we need this? mutos aren't destroyed until process exit */
47 /* Destructor (racy?) */
48 muto::~muto ()
49 {
50 while (visits)
51 release ();
52
53 HANDLE h = bruteforce;
54 bruteforce = NULL;
55 /* Just need to close the event handle */
56 if (h)
57 CloseHandle (h);
58 }
59 #endif
60
61 /* Acquire the lock. Argument is the number of milliseconds to wait for
62 the lock. Multiple visits from the same thread are allowed and should
63 be handled correctly.
64
65 Note: The goal here is to minimize, as much as possible, calls to the
66 OS. Hence the use of InterlockedIncrement, etc., rather than (much) more
67 expensive OS mutexes. */
68 int
69 muto::acquire (DWORD ms)
70 {
71 DWORD this_tid = GetCurrentThreadId ();
72 #if 0
73 if (exiting_thread)
74 return this_tid == exiting_thread;
75 #endif
76
77 if (tid != this_tid)
78 {
79 /* Increment the waiters part of the class. Need to do this first to
80 avoid potential races. */
81 LONG was_waiting = InterlockedIncrement (&waiters);
82
83 /* This is deceptively simple. Basically, it allows multiple attempts to
84 lock the same muto to succeed without attempting to manipulate sync.
85 If the muto is already locked then this thread will wait for ms until
86 it is signalled by muto::release. Then it will attempt to grab the
87 sync field. If it succeeds, then this thread owns the muto.
88
89 There is a pathological condition where a thread times out waiting for
90 bruteforce but the release code triggers the bruteforce event. In this
91 case, it is possible for a thread which is going to wait for bruteforce
92 to wake up immediately. It will then attempt to grab sync but will fail
93 and go back to waiting. */
94 if (tid != this_tid && (was_waiting || InterlockedExchange (&sync, 1) != 0))
95 {
96 switch (WaitForSingleObject (bruteforce, ms))
97 {
98 case WAIT_OBJECT_0:
99 goto gotit;
100 break;
101 default:
102 InterlockedDecrement (&waiters);
103 return 0; /* failed. */
104 }
105 }
106 }
107
108 gotit:
109 tid = this_tid; /* register this thread. */
110 return ++visits; /* Increment visit count. */
111 }
112
113 /* Return the muto lock. Needs to be called once per every acquire. */
114 int
115 muto::release ()
116 {
117 DWORD this_tid = GetCurrentThreadId ();
118
119 if (tid != this_tid || !visits)
120 {
121 SetLastError (ERROR_NOT_OWNER); /* Didn't have the lock. */
122 return 0; /* failed. */
123 }
124
125 /* FIXME: Need to check that other thread has not exited, too. */
126 if (!--visits)
127 {
128 tid = 0; /* We were the last unlocker. */
129 (void) InterlockedExchange (&sync, 0); /* Reset trigger. */
130 /* This thread had incremented waiters but had never decremented it.
131 Decrement it now. If it is >= 0 then there are possibly other
132 threads waiting for the lock, so trigger bruteforce. */
133 if (InterlockedDecrement (&waiters) >= 0)
134 (void) SetEvent (bruteforce); /* Wake up one of the waiting threads */
135 }
136
137 return 1; /* success. */
138 }
139
140 bool
141 muto::acquired ()
142 {
143 return tid == GetCurrentThreadId ();
144 }
145
146 /* Call only when we're exiting. This is not thread safe. */
147 void
148 muto::reset ()
149 {
150 visits = sync = tid = 0;
151 InterlockedExchange (&waiters, -1);
152 if (bruteforce)
153 {
154 CloseHandle (bruteforce);
155 bruteforce = CreateEvent (&sec_none_nih, FALSE, FALSE, name);
156 }
157 }
This page took 0.044452 seconds and 6 git commands to generate.