1 1.1 christos /* Plain recursive mutexes (native Windows implementation). 2 1.1 christos Copyright (C) 2005-2020 Free Software Foundation, Inc. 3 1.1 christos 4 1.1 christos This program is free software; you can redistribute it and/or modify 5 1.1 christos it under the terms of the GNU General Public License as published by 6 1.1 christos the Free Software Foundation; either version 3, or (at your option) 7 1.1 christos any later version. 8 1.1 christos 9 1.1 christos This program is distributed in the hope that it will be useful, 10 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 11 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 1.1 christos GNU General Public License for more details. 13 1.1 christos 14 1.1 christos You should have received a copy of the GNU General Public License 15 1.1 christos along with this program; if not, see <https://www.gnu.org/licenses/>. */ 16 1.1 christos 17 1.1 christos /* Written by Bruno Haible <bruno (at) clisp.org>, 2005. 18 1.1 christos Based on GCC's gthr-win32.h. */ 19 1.1 christos 20 1.1 christos #include <config.h> 21 1.1 christos 22 1.1 christos /* Specification. */ 23 1.1 christos #include "windows-recmutex.h" 24 1.1 christos 25 1.1 christos #include <errno.h> 26 1.1 christos 27 1.1 christos void 28 1.1 christos glwthread_recmutex_init (glwthread_recmutex_t *mutex) 29 1.1 christos { 30 1.1 christos mutex->owner = 0; 31 1.1 christos mutex->depth = 0; 32 1.1 christos InitializeCriticalSection (&mutex->lock); 33 1.1 christos mutex->guard.done = 1; 34 1.1 christos } 35 1.1 christos 36 1.1 christos int 37 1.1 christos glwthread_recmutex_lock (glwthread_recmutex_t *mutex) 38 1.1 christos { 39 1.1 christos if (!mutex->guard.done) 40 1.1 christos { 41 1.1 christos if (InterlockedIncrement (&mutex->guard.started) == 0) 42 1.1 christos /* This thread is the first one to need this mutex. Initialize it. */ 43 1.1 christos glwthread_recmutex_init (mutex); 44 1.1 christos else 45 1.1 christos { 46 1.1 christos /* Don't let mutex->guard.started grow and wrap around. */ 47 1.1 christos InterlockedDecrement (&mutex->guard.started); 48 1.1 christos /* Yield the CPU while waiting for another thread to finish 49 1.1 christos initializing this mutex. */ 50 1.1 christos while (!mutex->guard.done) 51 1.1 christos Sleep (0); 52 1.1 christos } 53 1.1 christos } 54 1.1 christos { 55 1.1 christos DWORD self = GetCurrentThreadId (); 56 1.1 christos if (mutex->owner != self) 57 1.1 christos { 58 1.1 christos EnterCriticalSection (&mutex->lock); 59 1.1 christos mutex->owner = self; 60 1.1 christos } 61 1.1 christos if (++(mutex->depth) == 0) /* wraparound? */ 62 1.1 christos { 63 1.1 christos mutex->depth--; 64 1.1 christos return EAGAIN; 65 1.1 christos } 66 1.1 christos } 67 1.1 christos return 0; 68 1.1 christos } 69 1.1 christos 70 1.1 christos int 71 1.1 christos glwthread_recmutex_trylock (glwthread_recmutex_t *mutex) 72 1.1 christos { 73 1.1 christos if (!mutex->guard.done) 74 1.1 christos { 75 1.1 christos if (InterlockedIncrement (&mutex->guard.started) == 0) 76 1.1 christos /* This thread is the first one to need this mutex. Initialize it. */ 77 1.1 christos glwthread_recmutex_init (mutex); 78 1.1 christos else 79 1.1 christos { 80 1.1 christos /* Don't let mutex->guard.started grow and wrap around. */ 81 1.1 christos InterlockedDecrement (&mutex->guard.started); 82 1.1 christos /* Let another thread finish initializing this mutex, and let it also 83 1.1 christos lock this mutex. */ 84 1.1 christos return EBUSY; 85 1.1 christos } 86 1.1 christos } 87 1.1 christos { 88 1.1 christos DWORD self = GetCurrentThreadId (); 89 1.1 christos if (mutex->owner != self) 90 1.1 christos { 91 1.1 christos if (!TryEnterCriticalSection (&mutex->lock)) 92 1.1 christos return EBUSY; 93 1.1 christos mutex->owner = self; 94 1.1 christos } 95 1.1 christos if (++(mutex->depth) == 0) /* wraparound? */ 96 1.1 christos { 97 1.1 christos mutex->depth--; 98 1.1 christos return EAGAIN; 99 1.1 christos } 100 1.1 christos } 101 1.1 christos return 0; 102 1.1 christos } 103 1.1 christos 104 1.1 christos int 105 1.1 christos glwthread_recmutex_unlock (glwthread_recmutex_t *mutex) 106 1.1 christos { 107 1.1 christos if (mutex->owner != GetCurrentThreadId ()) 108 1.1 christos return EPERM; 109 1.1 christos if (mutex->depth == 0) 110 1.1 christos return EINVAL; 111 1.1 christos if (--(mutex->depth) == 0) 112 1.1 christos { 113 1.1 christos mutex->owner = 0; 114 1.1 christos LeaveCriticalSection (&mutex->lock); 115 1.1 christos } 116 1.1 christos return 0; 117 1.1 christos } 118 1.1 christos 119 1.1 christos int 120 1.1 christos glwthread_recmutex_destroy (glwthread_recmutex_t *mutex) 121 1.1 christos { 122 1.1 christos if (mutex->owner != 0) 123 1.1 christos return EBUSY; 124 1.1 christos DeleteCriticalSection (&mutex->lock); 125 1.1 christos mutex->guard.done = 0; 126 1.1 christos return 0; 127 1.1 christos } 128