18dffb485Schristos /* Plain recursive mutexes (native Windows implementation). 2*4b169a6bSchristos Copyright (C) 2005-2022 Free Software Foundation, Inc. 38dffb485Schristos 4*4b169a6bSchristos This file is free software: you can redistribute it and/or modify 5*4b169a6bSchristos it under the terms of the GNU Lesser General Public License as 6*4b169a6bSchristos published by the Free Software Foundation; either version 2.1 of the 7*4b169a6bSchristos License, or (at your option) any later version. 88dffb485Schristos 9*4b169a6bSchristos This file is distributed in the hope that it will be useful, 108dffb485Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 118dffb485Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12*4b169a6bSchristos GNU Lesser General Public License for more details. 138dffb485Schristos 14*4b169a6bSchristos You should have received a copy of the GNU Lesser General Public License 15*4b169a6bSchristos along with this program. If not, see <https://www.gnu.org/licenses/>. */ 168dffb485Schristos 178dffb485Schristos /* Written by Bruno Haible <bruno@clisp.org>, 2005. 188dffb485Schristos Based on GCC's gthr-win32.h. */ 198dffb485Schristos 208dffb485Schristos #include <config.h> 218dffb485Schristos 228dffb485Schristos /* Specification. */ 238dffb485Schristos #include "windows-recmutex.h" 248dffb485Schristos 258dffb485Schristos #include <errno.h> 268dffb485Schristos 278dffb485Schristos void glwthread_recmutex_init(glwthread_recmutex_t * mutex)288dffb485Schristosglwthread_recmutex_init (glwthread_recmutex_t *mutex) 298dffb485Schristos { 308dffb485Schristos mutex->owner = 0; 318dffb485Schristos mutex->depth = 0; 328dffb485Schristos InitializeCriticalSection (&mutex->lock); 338dffb485Schristos mutex->guard.done = 1; 348dffb485Schristos } 358dffb485Schristos 368dffb485Schristos int glwthread_recmutex_lock(glwthread_recmutex_t * mutex)378dffb485Schristosglwthread_recmutex_lock (glwthread_recmutex_t *mutex) 388dffb485Schristos { 398dffb485Schristos if (!mutex->guard.done) 408dffb485Schristos { 418dffb485Schristos if (InterlockedIncrement (&mutex->guard.started) == 0) 428dffb485Schristos /* This thread is the first one to need this mutex. Initialize it. */ 438dffb485Schristos glwthread_recmutex_init (mutex); 448dffb485Schristos else 458dffb485Schristos { 468dffb485Schristos /* Don't let mutex->guard.started grow and wrap around. */ 478dffb485Schristos InterlockedDecrement (&mutex->guard.started); 488dffb485Schristos /* Yield the CPU while waiting for another thread to finish 498dffb485Schristos initializing this mutex. */ 508dffb485Schristos while (!mutex->guard.done) 518dffb485Schristos Sleep (0); 528dffb485Schristos } 538dffb485Schristos } 548dffb485Schristos { 558dffb485Schristos DWORD self = GetCurrentThreadId (); 568dffb485Schristos if (mutex->owner != self) 578dffb485Schristos { 588dffb485Schristos EnterCriticalSection (&mutex->lock); 598dffb485Schristos mutex->owner = self; 608dffb485Schristos } 618dffb485Schristos if (++(mutex->depth) == 0) /* wraparound? */ 628dffb485Schristos { 638dffb485Schristos mutex->depth--; 648dffb485Schristos return EAGAIN; 658dffb485Schristos } 668dffb485Schristos } 678dffb485Schristos return 0; 688dffb485Schristos } 698dffb485Schristos 708dffb485Schristos int glwthread_recmutex_trylock(glwthread_recmutex_t * mutex)718dffb485Schristosglwthread_recmutex_trylock (glwthread_recmutex_t *mutex) 728dffb485Schristos { 738dffb485Schristos if (!mutex->guard.done) 748dffb485Schristos { 758dffb485Schristos if (InterlockedIncrement (&mutex->guard.started) == 0) 768dffb485Schristos /* This thread is the first one to need this mutex. Initialize it. */ 778dffb485Schristos glwthread_recmutex_init (mutex); 788dffb485Schristos else 798dffb485Schristos { 808dffb485Schristos /* Don't let mutex->guard.started grow and wrap around. */ 818dffb485Schristos InterlockedDecrement (&mutex->guard.started); 828dffb485Schristos /* Let another thread finish initializing this mutex, and let it also 838dffb485Schristos lock this mutex. */ 848dffb485Schristos return EBUSY; 858dffb485Schristos } 868dffb485Schristos } 878dffb485Schristos { 888dffb485Schristos DWORD self = GetCurrentThreadId (); 898dffb485Schristos if (mutex->owner != self) 908dffb485Schristos { 918dffb485Schristos if (!TryEnterCriticalSection (&mutex->lock)) 928dffb485Schristos return EBUSY; 938dffb485Schristos mutex->owner = self; 948dffb485Schristos } 958dffb485Schristos if (++(mutex->depth) == 0) /* wraparound? */ 968dffb485Schristos { 978dffb485Schristos mutex->depth--; 988dffb485Schristos return EAGAIN; 998dffb485Schristos } 1008dffb485Schristos } 1018dffb485Schristos return 0; 1028dffb485Schristos } 1038dffb485Schristos 1048dffb485Schristos int glwthread_recmutex_unlock(glwthread_recmutex_t * mutex)1058dffb485Schristosglwthread_recmutex_unlock (glwthread_recmutex_t *mutex) 1068dffb485Schristos { 1078dffb485Schristos if (mutex->owner != GetCurrentThreadId ()) 1088dffb485Schristos return EPERM; 1098dffb485Schristos if (mutex->depth == 0) 1108dffb485Schristos return EINVAL; 1118dffb485Schristos if (--(mutex->depth) == 0) 1128dffb485Schristos { 1138dffb485Schristos mutex->owner = 0; 1148dffb485Schristos LeaveCriticalSection (&mutex->lock); 1158dffb485Schristos } 1168dffb485Schristos return 0; 1178dffb485Schristos } 1188dffb485Schristos 1198dffb485Schristos int glwthread_recmutex_destroy(glwthread_recmutex_t * mutex)1208dffb485Schristosglwthread_recmutex_destroy (glwthread_recmutex_t *mutex) 1218dffb485Schristos { 1228dffb485Schristos if (mutex->owner != 0) 1238dffb485Schristos return EBUSY; 1248dffb485Schristos DeleteCriticalSection (&mutex->lock); 1258dffb485Schristos mutex->guard.done = 0; 1268dffb485Schristos return 0; 1278dffb485Schristos } 128