]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/sync.cc
import winsup-2000-02-17 snapshot
[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 1999 Cygnus Solutions.
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 <stdlib.h>
18 #include <time.h>
19 #include <sys/wait.h>
20 #include <errno.h>
21 #include <stdlib.h>
22 #include "winsup.h"
23
24 /* Constructor */
25 muto::muto(int inh, const char *name) : sync (0), visits(0), waiters(-1), tid (0)
26 {
27 /* Create event which is used in the fallback case when blocking is necessary */
28 if (!(bruteforce = CreateEvent (inh ? &sec_all_nih : &sec_none_nih, FALSE, FALSE, name)))
29 {
30 DWORD oerr = GetLastError ();
31 SetLastError (oerr);
32 return;
33 }
34 }
35
36 /* Destructor */
37 muto::~muto ()
38 {
39 /* Just need to close the event handle */
40 if (bruteforce)
41 CloseHandle (bruteforce);
42 }
43
44 /* Acquire the lock. Argument is the number of milliseconds to wait for
45 the lock. Multiple visits from the same thread are allowed and should
46 be handled correctly. */
47 int
48 muto::acquire (DWORD ms)
49 {
50 DWORD this_tid = GetCurrentThreadId ();
51
52 if (tid != this_tid)
53 {
54 /* Increment the waiters part of the class. Need to do this first to
55 avoid potential races. */
56 LONG was_waiting = InterlockedIncrement (&waiters);
57
58 /* This is deceptively simple. Basically, it allows multiple attempts to
59 lock the same muto to succeed without attempting to manipulate sync.
60 If the muto is already locked then this thread will wait for ms until
61 it is signalled by muto::release. Then it will attempt to grab the
62 sync field. If it succeeds, then this thread owns the mutex.
63
64 There is a pathological condition where a thread times out waiting for
65 bruteforce but the release code triggers the bruteforce event. In this
66 case, it is possible for a thread which is going to wait for bruteforce
67 to wake up immediately. It will then attempt to grab sync but will fail
68 and go back to waiting. */
69 while (tid != this_tid && (was_waiting || InterlockedExchange (&sync, 1) != 0))
70 {
71 switch (WaitForSingleObject (bruteforce, ms))
72 {
73 case WAIT_OBJECT_0:
74 was_waiting = 0;
75 break;
76 default:
77 InterlockedDecrement (&waiters);
78 return 0; /* failed. */
79 }
80 }
81 }
82
83 tid = this_tid; /* register this thread. */
84 return ++visits; /* Increment visit count. */
85 }
86
87 /* Return the muto lock. Needs to be called once per every acquire. */
88 int
89 muto::release ()
90 {
91 DWORD this_tid = GetCurrentThreadId ();
92
93 if (tid != this_tid || !visits)
94 {
95 SetLastError (ERROR_NOT_OWNER); /* Didn't have the lock. */
96 return 0; /* failed. */
97 }
98
99 /* FIXME: Need to check that other thread has not exited, too. */
100 if (!--visits)
101 {
102 tid = 0; /* We were the last unlocker. */
103 InterlockedExchange (&sync, 0); /* Reset trigger. */
104 /* This thread had incremented waiters but had never decremented it.
105 Decrement it now. If it is >= 0 then there are possibly other
106 threads waiting for the lock, so trigger bruteforce. */
107 if (InterlockedDecrement (&waiters) >= 0)
108 (void) SetEvent (bruteforce); /* Wake up one of the waiting threads */
109 }
110
111 return 1; /* success. */
112 }
This page took 0.100041 seconds and 6 git commands to generate.