]>
sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/sync.cc
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 Cygnus Solutions.
9 Written by Christopher Faylor <cgf@cygnus.com>
11 This file is part of Cygwin.
13 This software is a copyrighted work licensed under the terms of the
14 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
26 muto NO_COPY muto_start
;
28 #undef WaitForSingleObject
31 muto::muto (int inh
, const char *s
) : sync (0), visits(0), waiters(-1), tid (0), next (NULL
)
33 /* Create event which is used in the fallback case when blocking is necessary */
34 if (!(bruteforce
= CreateEvent (inh
? &sec_all_nih
: &sec_none_nih
, FALSE
, FALSE
, name
)))
36 DWORD oerr
= GetLastError ();
43 /* Destructor (racy?) */
49 HANDLE h
= bruteforce
;
51 /* Just need to close the event handle */
56 /* Acquire the lock. Argument is the number of milliseconds to wait for
57 the lock. Multiple visits from the same thread are allowed and should
60 Note: The goal here is to minimize, as much as possible, calls to the
61 OS. Hence the use of InterlockedIncrement, etc., rather than (much) more
62 expensive OS mutexes. */
64 muto::acquire (DWORD ms
)
66 DWORD this_tid
= GetCurrentThreadId ();
70 /* Increment the waiters part of the class. Need to do this first to
71 avoid potential races. */
72 LONG was_waiting
= InterlockedIncrement (&waiters
);
74 /* This is deceptively simple. Basically, it allows multiple attempts to
75 lock the same muto to succeed without attempting to manipulate sync.
76 If the muto is already locked then this thread will wait for ms until
77 it is signalled by muto::release. Then it will attempt to grab the
78 sync field. If it succeeds, then this thread owns the muto.
80 There is a pathological condition where a thread times out waiting for
81 bruteforce but the release code triggers the bruteforce event. In this
82 case, it is possible for a thread which is going to wait for bruteforce
83 to wake up immediately. It will then attempt to grab sync but will fail
84 and go back to waiting. */
85 while (tid
!= this_tid
&& (was_waiting
|| InterlockedExchange (&sync
, 1) != 0))
87 switch (WaitForSingleObject (bruteforce
, ms
))
93 InterlockedDecrement (&waiters
);
94 return 0; /* failed. */
100 tid
= this_tid
; /* register this thread. */
101 return ++visits
; /* Increment visit count. */
104 /* Return the muto lock. Needs to be called once per every acquire. */
108 DWORD this_tid
= GetCurrentThreadId ();
110 if (tid
!= this_tid
|| !visits
)
112 SetLastError (ERROR_NOT_OWNER
); /* Didn't have the lock. */
113 return 0; /* failed. */
116 /* FIXME: Need to check that other thread has not exited, too. */
119 tid
= 0; /* We were the last unlocker. */
120 (void) InterlockedExchange (&sync
, 0); /* Reset trigger. */
121 /* This thread had incremented waiters but had never decremented it.
122 Decrement it now. If it is >= 0 then there are possibly other
123 threads waiting for the lock, so trigger bruteforce. */
124 if (InterlockedDecrement (&waiters
) >= 0)
125 (void) SetEvent (bruteforce
); /* Wake up one of the waiting threads */
128 return 1; /* success. */
131 /* Call only when we're exiting. This is not thread safe. */
135 visits
= sync
= tid
= 0;
136 InterlockedExchange (&waiters
, -1);
139 CloseHandle (bruteforce
);
140 bruteforce
= CreateEvent (&sec_none_nih
, FALSE
, FALSE
, name
);
This page took 0.108298 seconds and 6 git commands to generate.