Bump GPLv2+ to GPLv3+ for some files, clarify BSD 2-clause. Everything else stays under GPLv3+. New Linking Exception exempts resulting executables from LGPLv3 section 4. Add CONTRIBUTORS file to keep track of licensing. Remove 'Copyright Red Hat Inc' comments. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
		
			
				
	
	
		
			143 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			143 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* 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.
 | |
| 
 | |
| 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 "winsup.h"
 | |
| #include "miscfuncs.h"
 | |
| #include "sync.h"
 | |
| #include "thread.h"
 | |
| #include "cygtls.h"
 | |
| 
 | |
| #undef WaitForSingleObject
 | |
| 
 | |
| muto NO_COPY lock_process::locker;
 | |
| 
 | |
| void
 | |
| muto::grab ()
 | |
| {
 | |
|   tls = &_my_tls;
 | |
| }
 | |
| 
 | |
| /* Constructor */
 | |
| muto *
 | |
| muto::init (const char *s)
 | |
| {
 | |
|   char *already_exists = (char *) InterlockedExchangePointer ((PVOID *) &name,
 | |
| 							      (PVOID) s);
 | |
|   if (already_exists)
 | |
|     while (!bruteforce)
 | |
|       yield ();
 | |
|   else
 | |
|     {
 | |
|       waiters = -1;
 | |
|       /* Create event which is used in the fallback case when blocking is necessary */
 | |
|       bruteforce = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
 | |
|       if (!bruteforce)
 | |
| 	  api_fatal ("couldn't allocate muto '%s', %E", s);
 | |
|     }
 | |
| 
 | |
|   return this;
 | |
| }
 | |
| 
 | |
| #if 0 /* FIXME: Do we need this? mutos aren't destroyed until process exit */
 | |
| /* Destructor (racy?) */
 | |
| muto::~muto ()
 | |
| {
 | |
|   while (visits)
 | |
|     release ();
 | |
| 
 | |
|   HANDLE h = bruteforce;
 | |
|   bruteforce = NULL;
 | |
|   /* Just need to close the event handle */
 | |
|   if (h)
 | |
|     CloseHandle (h);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /* 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.
 | |
| 
 | |
|    Note: The goal here is to minimize, as much as possible, calls to the
 | |
|    OS.  Hence the use of InterlockedIncrement, etc., rather than (much) more
 | |
|    expensive OS mutexes.  */
 | |
| int
 | |
| muto::acquire (DWORD ms)
 | |
| {
 | |
|   void *this_tls = &_my_tls;
 | |
| 
 | |
|   if (tls != this_tls)
 | |
|     {
 | |
|       /* Increment the waiters part of the class.  Need to do this first to
 | |
| 	 avoid potential races. */
 | |
|       LONG was_waiting = ms ? InterlockedIncrement (&waiters) : 0;
 | |
| 
 | |
|       while (was_waiting || InterlockedExchange (&sync, 1) != 0)
 | |
| 	switch (WaitForSingleObject (bruteforce, ms))
 | |
| 	    {
 | |
| 	    case WAIT_OBJECT_0:
 | |
| 	      was_waiting = 0;
 | |
| 	      break;
 | |
| 	    default:
 | |
| 	      return 0;	/* failed. */
 | |
| 	    }
 | |
| 
 | |
|       /* Have to do it this way to avoid a race */
 | |
|       if (!ms)
 | |
| 	InterlockedIncrement (&waiters);
 | |
| 
 | |
|       tls = this_tls;	/* register this thread. */
 | |
|     }
 | |
| 
 | |
|   return ++visits;	/* Increment visit count. */
 | |
| }
 | |
| 
 | |
| bool
 | |
| muto::acquired ()
 | |
| {
 | |
|   return tls == &_my_tls;
 | |
| }
 | |
| 
 | |
| /* Return the muto lock.  Needs to be called once per every acquire. */
 | |
| int
 | |
| muto::release (_cygtls *this_tls)
 | |
| {
 | |
|   if (tls != this_tls || !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)
 | |
|     {
 | |
|       tls = 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)
 | |
| 	SetEvent (bruteforce); /* Wake up one of the waiting threads */
 | |
|       else if (*name == '!')
 | |
| 	{
 | |
| 	  CloseHandle (bruteforce);	/* If *name == '!' and there are no
 | |
| 					   other waiters, then this is the
 | |
| 					   last time this muto will ever be
 | |
| 					   used, so close the handle. */
 | |
| #ifdef DEBUGGING
 | |
| 	  bruteforce = NULL;
 | |
| #endif
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   return 1;	/* success. */
 | |
| }
 |