root/branches/windows-client/src/common/gen-locks/gen-win-locks.c @ 8527

Revision 8527, 9.3 KB (checked in by sampson, 3 years ago)

Working on gen_locks

  • Property svn:executable set to *
Line 
1/*
2 * (C) 2001 Clemson University and The University of Chicago
3 *
4 * See COPYING in top-level directory.
5 */
6
7
8/* This code implements generic locking that can be turned on or off at
9 * compile time.
10 */
11
12#include <stdlib.h>
13#include <errno.h>
14
15#include "gen-locks.h"
16
17/***************************************************************
18 * visible functions
19 */
20
21#ifndef __GEN_NULL_LOCKING__
22
23/* Global variables */
24/* TODO: may need to init and delete in DLL enter/exit functions */
25LPCRITICAL_SECTION cond_list_lock = NULL;
26LPCRITICAL_SECTION cond_test_init_lock = NULL;
27
28pgen_cond_t cond_list_head = NULL;
29pgen_cond_t cond_list_tail = NULL;
30
31/*
32 * gen_mutex_init()
33 *
34 * initializes a previously declared mutex
35 *
36 * returns 0 on success, -1 and sets errno on failure.
37 */
38int gen_win_mutex_init(
39    HANDLE *mut)
40{
41    *mut = CreateMutex(NULL, false, NULL);
42    return (*mut) ? 0 : -1;
43}
44
45/*
46 * gen_mutex_lock()
47 *
48 * blocks until it obtains a mutex lock on the given mutex
49 *
50 * returns 0 on success, -1 and sets errno on failure.
51 */
52int gen_win_mutex_lock(
53    HANDLE *mut)
54{
55    DWORD dwWaitResult;
56
57    dwWaitResult = WaitForSingleObject(*mut, INFINITE);
58
59    return (dwWaitResult == WAIT_OBJECT_0 || dwWaitResult == WAIT_ABANDONED) ? 0 : -1;
60}
61
62
63/*
64 * gen_mutex_unlock()
65 *
66 * releases a lock held on a mutex
67 *
68 * returns 0 on success, -1 and sets errno on failure
69 */
70int gen_win_mutex_unlock(
71    HANDLE *mut)
72{
73    BOOL rc = ReleaseMutex(*mut);
74
75    return (rc) ? 0 : -1;
76}
77
78
79/*
80 * pthread_mutex_trylock()
81 *
82 * nonblocking attempt to acquire a lock.
83 *
84 * returns 0 on success, -1 and sets errno on failure, sets errno to EBUSY
85 * if it cannot obtain the lock
86 */
87int gen_win_mutex_trylock(
88    HANDLE *mut)
89{
90    DWORD dwWaitResult;
91    int rc;
92     
93    dwWaitResult = WaitForSingleObject(*mut, 0);
94    if (dwWaitResult == WAIT_OBJECT_0 || dwWaitResult == WAIT_ABANDONED)
95    {
96        rc = 0;
97    }
98    else
99    {
100        rc = -1;
101        if (dwWaitResult == WAIT_TIMEOUT)
102        {
103            errno = EBUSY;
104        }
105        else
106        {
107            errno = GetLastError();
108        }
109    }
110
111    return rc;
112}
113
114/*
115 * gen_mutex_destroy()
116 *
117 * uninitializes the mutex and frees all memory associated with it.
118 *
119 * returns 0 on success, -errno on failure.
120 */
121int gen_win_mutex_destroy(
122    HANDLE *mut)
123{
124
125    if (!mut || *mut == INVALID_HANDLE_VALUE)
126    {
127        return (-EINVAL);
128    }
129   
130    CloseHandle(*mut);
131
132    return (0);
133}
134
135HANDLE gen_win_thread_self(void)
136{
137    return GetCurrentThread();
138}
139
140int gen_win_cond_destroy(pgen_cond_t *cond)
141{
142    pgen_cond_t cv;
143    int result = 0, result1 = 0, result2 = 0;
144
145    if(!cond || !(*cond))
146    {
147        return -EINVAL;
148    }
149   
150    if (*cond != GEN_COND_INITIALIZER)
151    {
152        EnterCriticalSection(cond_list_lock);
153
154        cv = *cond;
155
156        if (WaitForSingleObject(&(cv->semBlockLock), INFINITE) != WAIT_OBJECT_0)
157        {   
158            return GetLastError();
159        }
160
161        if ((result = gen_mutex_trylock(&(cv->mtxUnblockLock))) != 0)
162        {
163            ReleaseSemaphore(&(cv->semBlockLock), 1, NULL);
164            return result;
165        }
166
167        if (cv->nWaitersBlocked > cv->nWaitersGone)
168        {
169            if (!ReleaseSemaphore(&(cv->semBlockLock), 1, NULL))
170            {
171                result = GetLastError();
172            }
173            result1 = gen_mutex_unlock(&(cv->mtxUnblockLock));
174            result2 = EBUSY;
175        }
176        else
177        {
178            /* Now it is safe to destroy */
179            *cond = NULL;
180
181            if (CloseHandle(&(cv->semBlockLock)) != 0)
182            {
183                result = GetLastError();
184            }
185            if (CloseHandle(&(cv->semBlockQueue)) != 0)
186            {
187                result1 = GetLastError();
188            }
189            if ((result2 = gen_mutex_unlock(&(cv->mtxUnblockLock))) == 0)
190            {
191                result2 = gen_mutex_destroy(&(cv->mtxUnblockLock));
192            }
193
194            /* Unlink the CV from the list */
195            if (cond_list_head == cv)
196            {
197                cond_list_head = cv->next;
198            }
199            else
200            {
201                cv->prev->next = cv->next;
202            }
203
204            if (cond_list_tail == cv)
205            {
206                cond_list_tail = cv->prev;
207            }
208            else {
209                cv->next->prev = cv->prev;
210            }
211
212            free(cv);
213        }
214
215        LeaveCriticalSection(cond_list_lock);
216    }
217    else
218    {
219        EnterCriticalSection(cond_test_init_lock);
220
221        if (*cond == GEN_COND_INITIALIZER)
222        {
223            *cond = NULL;
224        }
225        else
226        {
227            result = EBUSY;
228        }
229
230        LeaveCriticalSection(cond_test_init_lock);
231    }
232
233    return ((result != 0) ? result : ((result1 != 0) ? result1 : result2));
234}
235
236typedef struct
237{
238    gen_mutex_t *mutexPtr;
239    pgen_cond_t cv;
240    int *resultPtr;
241} cond_wait_cleanup_args_t;
242
243static void __cdecl cond_wait_cleanup(void *args)
244{
245    cond_wait_cleanup_args_t *cleanup_args = (cond_wait_cleanup_args_t *) args;
246    pgen_cond_t cv = cleanup_args->cv;
247    int *resultPtr = cleanup_args->resultPtr;
248    int nSignalsWasLeft;
249    int result;
250
251    if ((result = gen_mutex_lock(&(cv->mtxUnblockLock))) != 0)
252    {
253        *resultPtr = result;
254        return;
255    }
256
257    if ((nSignalsWasLeft = cv->nWaitersToUnblock) != 0)
258    {
259        --(cv->nWaitersToUnblock);
260    }
261    else if (INT_MAX / 2 == ++(cv->nWaitersGone))
262    {
263        if (WaitForSingleObject(&(cv->semBlockLock), INFINITE) != 0)
264        {
265            *resultPtr = (int) GetLastError();
266            return;
267        }
268        cv->nWaitersBlocked -= cv->nWaitersGone;
269        if (!ReleaseSemaphore(&(cv->semBlockLock), 1, NULL))
270        {
271            *resultPtr = (int) GetLastError();
272            return;
273        }
274        cv->nWaitersGone = 0;
275    }
276
277    if ((result = gen_mutex_unlock(&(cv->mtxUnblockLock))) != 0)
278    {
279        *resultPtr = result;
280        return;
281    }
282
283    if (nSignalsWasLeft == 1)
284    {
285        if (!ReleaseSemaphore(&(cv->semBlockLock), 1, NULL))
286        {
287            *resultPtr = (int) GetLastError();
288            return;
289        }
290    }
291
292    if ((result = gen_mutex_lock(cleanup_args->mutexPtr)) != 0)
293    {
294        *resultPtr = result;
295    }
296
297}
298
299static __inline int cond_timedwait(pgen_cond_t *cond,
300                                   HANDLE *mutex, const struct timespec *abstime)
301{
302    int result = 0;
303    pgen_cond_t cv;
304    cond_wait_cleanup_args_t cleanup_args;
305
306    if (cond == NULL || *cond == NULL)
307    {
308        return EINVAL;
309    }
310
311    if (*cond == GEN_COND_INITIALIZER)
312    {
313        result = cond_check_need_init(cond);
314    }
315
316    if (result != 0 && result != EBUSY)
317    {
318        return result;
319    }
320
321    cv = *cond;
322
323    if (WaitForSingleObject(&(cv->semBlockLock), INFINITE) != 0)
324    {
325        return (int) GetLastError();
326    }
327
328    ++(cv->nWaitersBlocked);
329
330    if (!ReleaseSemaphore(&(cv->semBlockLock), 1, NULL))
331    {
332        return (int) GetLastError();
333    }
334
335    cleanup_args.mutexPtr = mutex;
336    cleanup_args.cv = cv;
337    cleanup_args.resultPtr = &result;
338
339    // TODO: pthread_cleanup_push(cond_wait_cleanup, (void*) &cleanup_args);
340
341    /* Now we can release mutex and... */
342    if ((result = gen_mutex_unlock(mutex)) == 0)
343    {
344
345    }
346
347    return result;
348}
349
350int gen_win_cond_wait(pgen_cond_t *cond, HANDLE *mut)
351{
352    return pthread_cond_wait(cond, mut);
353}
354
355int gen_win_cond_timedwait(pgen_cond_t *cond, HANDLE *mut,
356                             const struct timespec *abstime)
357{
358    return pthread_cond_timedwait(cond, mut, abstime);
359}
360
361int gen_win_cond_signal(pgen_cond_t *cond)
362{
363    return pthread_cond_signal(cond);
364}
365
366int gen_win_cond_broadcast(pgen_cond_t *cond)
367{
368    return pthread_cond_broadcast(cond);
369}
370
371int gen_win_cond_init(pgen_cond_t *cond)
372{
373    int rc;
374    pgen_cond_t cv = NULL;
375
376    if (!cond)
377    {
378        return EINVAL;
379    }
380
381    /* Allocate condition variable */
382    cv = (pgen_cond_t) calloc(1, sizeof(*cv));
383    if (cv == NULL)
384    {
385        rc = ENOMEM;
386        goto DONE;
387    }
388
389    /* Create locking semaphore */
390    cv->semBlockLock = CreateSemaphore(NULL, 1, LONG_MAX, NULL);
391    if (cv->semBlockLock == NULL)
392    {
393        rc = (int) GetLastError();
394        goto FAIL0;
395    }
396
397    /* Create queue semaphore */
398    cv->semBlockQueue = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
399    if (cv->semBlockQueue == NULL)
400    {
401        rc = (int) GetLastError();
402        goto FAIL1;
403    }
404
405    /* Create unblock/lock mutex */
406    if ((rc = gen_mutex_init(&(cv->mtxUnblockLock))) != 0)
407    {
408        goto FAIL2;
409    }
410
411    rc = 0;
412
413    goto DONE;
414
415    /*
416     * Error conditions
417     */
418FAIL2:
419    CloseHandle(cv->semBlockQueue);
420
421FAIL1:
422    CloseHandle(cv->semBlockLock);
423
424FAIL0:
425    free(cv);
426    cv = NULL;
427
428DONE:
429    if (rc == 0)
430    {
431        if (cond_list_lock == NULL)
432        {
433            InitializeCriticalSection(cond_list_lock);
434        }
435
436        EnterCriticalSection(cond_list_lock);
437
438        cv->next = NULL;
439        cv->prev = cond_list_tail;
440
441        if (cond_list_tail != NULL)
442        {
443            cond_list_tail->next = cv;
444        }
445
446        cond_list_tail = cv;
447
448        if (cond_list_head == NULL)
449        {
450            cond_list_head = cv;
451        }
452
453        LeaveCriticalSection(cond_list_lock);
454
455    }
456
457    *cond = cv;
458
459    return rc;
460}
461
462#endif
463
464/*
465 * Local variables:
466 *  c-indent-level: 4
467 *  c-basic-offset: 4
468 * End:
469 *
470 * vim: ts=8 sts=4 sw=4 expandtab
471 */
Note: See TracBrowser for help on using the browser.