Imported Upstream version 3.2.0
[debian/amanda] / common-src / semaphore.c
1 /*
2  * Copyright (c) 2008, 2009, 2010 Zmanda, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 as published
6  * by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16  *
17  * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
19  */
20
21 /* GLib does not provide semaphores, which are useful in queue.c.
22    So, we implement it here. */
23
24 #include "amanda.h"
25 #include "semaphore.h"
26
27 semaphore_t* semaphore_new_with_value(int value) {
28     semaphore_t *rval;
29
30     if (!g_thread_supported())
31         return NULL;
32
33     rval = malloc(sizeof(*rval));
34     rval->value = value;
35     rval->mutex = g_mutex_new();
36     rval->decrement_cond = g_cond_new();
37     rval->zero_cond = g_cond_new();
38     
39     if (rval->mutex == NULL || rval->decrement_cond == NULL ||
40         rval->zero_cond == NULL) {
41         semaphore_free(rval);
42         return NULL;
43     } else {
44         return rval;
45     }
46 }
47
48 void semaphore_free(semaphore_t* o) {
49     g_mutex_free(o->mutex);
50     g_cond_free(o->decrement_cond);
51     g_cond_free(o->zero_cond);
52     free(o);
53 }
54
55 /* This function checks if the semaphore would is zero or negative.
56  * If so, the zero_cond is signalled. We assume that the mutex is
57  * locked. */
58 static void check_empty(semaphore_t * o) {
59     if (o->value <= 0) {
60         g_cond_broadcast(o->zero_cond);
61     }
62 }
63
64 void semaphore_increment(semaphore_t* o, unsigned int inc) {
65     g_return_if_fail(o != NULL);
66     g_return_if_fail(inc != 0);
67
68     semaphore_force_adjust(o, inc);
69 }
70
71 void semaphore_decrement(semaphore_t* o, unsigned int dec) {
72     int sdec;
73     g_return_if_fail(o != NULL);
74     sdec = (int) dec;
75     g_return_if_fail(sdec >= 0);
76
77     g_mutex_lock(o->mutex);
78     while (o->value < sdec) {
79         g_cond_wait(o->decrement_cond, o->mutex);
80     }
81     o->value -= sdec;
82     check_empty(o);
83     g_mutex_unlock(o->mutex);
84 }
85
86 void semaphore_force_adjust(semaphore_t* o, int inc) {
87     g_return_if_fail(o != NULL);
88
89     g_mutex_lock(o->mutex);
90     o->value += inc;
91     if (inc < 0)
92         check_empty(o);
93     else
94         g_cond_broadcast(o->decrement_cond);
95     g_mutex_unlock(o->mutex);
96
97 }
98
99 void semaphore_force_set(semaphore_t* o, int value) {
100     int oldvalue;
101     g_return_if_fail(o != NULL);
102     
103     g_mutex_lock(o->mutex);
104     oldvalue = o->value;
105     o->value = value;
106     if (value < oldvalue)
107         check_empty(o);
108     else
109         g_cond_broadcast(o->decrement_cond);
110     g_mutex_unlock(o->mutex);
111     
112 }
113
114 void semaphore_wait_empty(semaphore_t * o) {
115     g_return_if_fail(o != NULL);
116     
117     g_mutex_lock(o->mutex);
118     while (o->value > 0) {
119         g_cond_wait(o->zero_cond, o->mutex);
120     }
121     g_mutex_unlock(o->mutex);
122 }