Imported Upstream version 2.6.0p2
[debian/amanda] / device-src / tests / semaphore-test.c
1 /*
2  * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
3  *
4  * This library is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License version 2.1 as
6  * published by the Free Software Foundation.
7  *
8  * This library 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 Lesser General Public
11  * License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library; if not, write to the Free Software Foundation,
15  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
16  *
17  * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
18  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
19  */
20
21 #include "semaphore.h"
22 #include "amanda.h"
23 #include "util.h"
24
25 /*
26  * test that decrement waits properly
27  */
28
29 struct test_decr_wait_data {
30     semaphore_t *sem;
31     gboolean increment_called;
32 };
33
34 static gpointer
35 test_decr_wait_thread(gpointer datap)
36 {
37     struct test_decr_wait_data *data = datap;
38
39     /* should block */
40     semaphore_decrement(data->sem, 20);
41
42     /* if increment hasn't been called yet, that's an error. */
43     if (!data->increment_called)
44         return GINT_TO_POINTER(0);
45
46     return GINT_TO_POINTER(1);
47 }
48
49 static gboolean
50 test_decr_wait(void)
51 {
52     GThread *th;
53     struct test_decr_wait_data data = { NULL, FALSE };
54     int rv;
55
56     data.sem = semaphore_new_with_value(10),
57
58     /* die after 10 seconds (default signal disposition is to fail) */
59     alarm(10);
60
61     th = g_thread_create(test_decr_wait_thread, (gpointer)&data, TRUE, NULL);
62
63     /* sleep to give semaphore_decrement() a chance to block (or not). */
64     g_usleep(G_USEC_PER_SEC / 4);
65
66     /* and then increment the semaphore enough that the decrement can succeed */
67     data.increment_called = TRUE;
68     semaphore_increment(data.sem, 10);
69
70     /* join the thread and see how it fared. */
71     rv = GPOINTER_TO_INT(g_thread_join(th));
72
73     semaphore_free(data.sem);
74
75     if (rv == 1) {
76         printf(" PASS: semaphore-test.test_decr_wait\n");
77         return TRUE;
78     } else {
79         printf(" FAIL: semaphore-test.test_decr_wait\n");
80         return FALSE;
81     }
82 }
83
84
85 /*
86  * test that semaphore_wait_empty waits properly
87  */
88
89 static gpointer
90 test_wait_empty_thread(gpointer datap)
91 {
92     semaphore_t *sem = datap;
93
94     /* should block */
95     semaphore_decrement(sem, 20);
96
97     /* value should be 10 now (decremented from 30) */
98     if (sem->value != 10)
99         return GINT_TO_POINTER(1);
100
101     /* sleep for a bit */
102     g_usleep(G_USEC_PER_SEC / 4);
103
104     /* decrement those last 10, which should trigger the zero */
105     semaphore_decrement(sem, 10);
106
107     return GINT_TO_POINTER(0);
108 }
109
110 static gboolean
111 test_wait_empty(void)
112 {
113     GThread *th;
114     semaphore_t *sem = semaphore_new_with_value(10);
115     int rv;
116
117     /* die after 10 seconds (default signal disposition is to fail) */
118     alarm(10);
119
120     th = g_thread_create(test_wait_empty_thread, (gpointer)sem, TRUE, NULL);
121
122     /* sleep to give semaphore_decrement() a chance to block (or not). */
123     g_usleep(G_USEC_PER_SEC / 4);
124
125     /* add another 10, so decrement can hit zero next time it's called */
126     semaphore_increment(sem, 10);
127
128     /* and wait on the semaphore emptying */
129     semaphore_wait_empty(sem);
130
131     /* join the thread and see how it fared. */
132     rv = GPOINTER_TO_INT(g_thread_join(th));
133
134     semaphore_free(sem);
135
136     if (rv == 1) {
137         printf(" PASS: semaphore-test.test_wait_empty\n");
138         return TRUE;
139     } else {
140         printf(" FAIL: semaphore-test.test_wait_empty\n");
141         return FALSE;
142     }
143 }
144
145 /*
146  * test that semaphore_force_adjust correctly wakes both
147  * semaphore_decrement and semaphore_wait_empty.
148  */
149
150 static gpointer
151 test_force_adjust_thread(gpointer datap)
152 {
153     semaphore_t *sem = datap;
154
155     /* this should block */
156     semaphore_decrement(sem, 20);
157
158     /* and this should block, too - it's fun */
159     semaphore_wait_empty(sem);
160
161     return NULL;
162 }
163
164 static gboolean
165 test_force_adjust(void)
166 {
167     GThread *th;
168     semaphore_t *sem = semaphore_new_with_value(10);
169
170     /* die after 10 seconds (default signal disposition is to fail) */
171     alarm(10);
172
173     th = g_thread_create(test_force_adjust_thread, (gpointer)sem, TRUE, NULL);
174
175     /* sleep to give semaphore_decrement() a chance to block (or not). */
176     g_usleep(G_USEC_PER_SEC / 4);
177
178     /* add another 20, so decrement can proceed, but leave the value at 10 */
179     semaphore_force_adjust(sem, 20);
180
181     /* sleep to give semaphore_wait_empty() a chance to block (or not). */
182     g_usleep(G_USEC_PER_SEC / 4);
183
184     /* and empty out the semaphore */
185     semaphore_force_adjust(sem, -10);
186
187     g_thread_join(th);
188
189     semaphore_free(sem);
190
191     /* it we didn't hang yet, it's all good */
192     printf(" PASS: semaphore-test.test_force_adjust\n");
193     return TRUE;
194 }
195
196 /*
197  * test that semaphore_force_set correctly wakes both
198  * semaphore_decrement and semaphore_wait_empty.
199  */
200
201 static gpointer
202 test_force_set_thread(gpointer datap)
203 {
204     semaphore_t *sem = datap;
205
206     /* this should block */
207     semaphore_decrement(sem, 20);
208
209     /* and this should block, too - it's fun */
210     semaphore_wait_empty(sem);
211
212     return NULL;
213 }
214
215 static gboolean
216 test_force_set(void)
217 {
218     GThread *th;
219     semaphore_t *sem = semaphore_new_with_value(10);
220
221     /* die after 10 seconds (default signal disposition is to fail) */
222     alarm(10);
223
224     th = g_thread_create(test_force_set_thread, (gpointer)sem, TRUE, NULL);
225
226     /* sleep to give semaphore_decrement() a chance to block (or not). */
227     g_usleep(G_USEC_PER_SEC / 4);
228
229     /* set it to 30, so decrement can proceed, but leave the value at 10 */
230     semaphore_force_set(sem, 30);
231
232     /* sleep to give semaphore_wait_empty() a chance to block (or not). */
233     g_usleep(G_USEC_PER_SEC / 4);
234
235     /* and empty out the semaphore */
236     semaphore_force_set(sem, 0);
237
238     g_thread_join(th);
239
240     semaphore_free(sem);
241
242     /* it we didn't hang yet, it's all good */
243     printf(" PASS: semaphore-test.test_force_set\n");
244     return TRUE;
245 }
246
247 /*
248  * Main loop
249  */
250
251 int
252 main(void)
253 {
254     gboolean pass = TRUE;
255
256 #if defined(G_THREADS_ENABLED) && !defined(G_THREADS_IMPL_NONE)
257     amanda_thread_init();
258
259     pass = test_decr_wait() && pass;
260     pass = test_wait_empty() && pass;
261     pass = test_force_adjust() && pass;
262     pass = test_force_set() && pass;
263
264     return pass?0:1;
265 #else
266     printf("No thread support on this platform -- nothing to test\n");
267     return 0;
268 #endif
269 }