From 1fd5e000ace55b323124c7e556a7a864b972a5c4 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Thu, 17 Feb 2000 19:38:33 +0000 Subject: import winsup-2000-02-17 snapshot --- winsup/cygwin/sync.cc | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 winsup/cygwin/sync.cc (limited to 'winsup/cygwin/sync.cc') diff --git a/winsup/cygwin/sync.cc b/winsup/cygwin/sync.cc new file mode 100644 index 000000000..89d92ce06 --- /dev/null +++ b/winsup/cygwin/sync.cc @@ -0,0 +1,112 @@ +/* sync.cc: Synchronization functions for cygwin. + + This file implements the methods for controlling the "muto" class + which is intended to operate similarly to a mutex but attempts to + avoid making expensive calls to the kernel. + + Copyright 1999 Cygnus Solutions. + + Written by Christopher Faylor + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include +#include "winsup.h" + +/* Constructor */ +muto::muto(int inh, const char *name) : sync (0), visits(0), waiters(-1), tid (0) +{ + /* Create event which is used in the fallback case when blocking is necessary */ + if (!(bruteforce = CreateEvent (inh ? &sec_all_nih : &sec_none_nih, FALSE, FALSE, name))) + { + DWORD oerr = GetLastError (); + SetLastError (oerr); + return; + } +} + +/* Destructor */ +muto::~muto () +{ + /* Just need to close the event handle */ + if (bruteforce) + CloseHandle (bruteforce); +} + +/* Acquire the lock. Argument is the number of milliseconds to wait for + the lock. Multiple visits from the same thread are allowed and should + be handled correctly. */ +int +muto::acquire (DWORD ms) +{ + DWORD this_tid = GetCurrentThreadId (); + + if (tid != this_tid) + { + /* Increment the waiters part of the class. Need to do this first to + avoid potential races. */ + LONG was_waiting = InterlockedIncrement (&waiters); + + /* This is deceptively simple. Basically, it allows multiple attempts to + lock the same muto to succeed without attempting to manipulate sync. + If the muto is already locked then this thread will wait for ms until + it is signalled by muto::release. Then it will attempt to grab the + sync field. If it succeeds, then this thread owns the mutex. + + There is a pathological condition where a thread times out waiting for + bruteforce but the release code triggers the bruteforce event. In this + case, it is possible for a thread which is going to wait for bruteforce + to wake up immediately. It will then attempt to grab sync but will fail + and go back to waiting. */ + while (tid != this_tid && (was_waiting || InterlockedExchange (&sync, 1) != 0)) + { + switch (WaitForSingleObject (bruteforce, ms)) + { + case WAIT_OBJECT_0: + was_waiting = 0; + break; + default: + InterlockedDecrement (&waiters); + return 0; /* failed. */ + } + } + } + + tid = this_tid; /* register this thread. */ + return ++visits; /* Increment visit count. */ +} + +/* Return the muto lock. Needs to be called once per every acquire. */ +int +muto::release () +{ + DWORD this_tid = GetCurrentThreadId (); + + if (tid != this_tid || !visits) + { + SetLastError (ERROR_NOT_OWNER); /* Didn't have the lock. */ + return 0; /* failed. */ + } + + /* FIXME: Need to check that other thread has not exited, too. */ + if (!--visits) + { + tid = 0; /* We were the last unlocker. */ + InterlockedExchange (&sync, 0); /* Reset trigger. */ + /* This thread had incremented waiters but had never decremented it. + Decrement it now. If it is >= 0 then there are possibly other + threads waiting for the lock, so trigger bruteforce. */ + if (InterlockedDecrement (&waiters) >= 0) + (void) SetEvent (bruteforce); /* Wake up one of the waiting threads */ + } + + return 1; /* success. */ +} -- cgit v1.2.3