Imported Upstream version 3.2.0
[debian/amanda] / common-src / semaphore-test.c
1 /*
2  * Copyright (c) 2008,2009 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 #include "amanda.h"
22 #include "semaphore.h"
23 #include "testutils.h"
24 #include "util.h"
25
26 /*
27  * test that decrement waits properly
28  */
29
30 struct test_decr_wait_data {
31     semaphore_t *sem;
32     gboolean increment_called;
33 };
34
35 static gpointer
36 test_decr_wait_thread(gpointer datap)
37 {
38     struct test_decr_wait_data *data = datap;
39
40     /* should block */
41     semaphore_decrement(data->sem, 20);
42
43     /* if increment hasn't been called yet, that's an error. */
44     if (!data->increment_called)
45         return GINT_TO_POINTER(0);
46
47     return GINT_TO_POINTER(1);
48 }
49
50 static gboolean
51 test_decr_wait(void)
52 {
53     GThread *th;
54     struct test_decr_wait_data data = { NULL, FALSE };
55     int rv;
56
57     data.sem = semaphore_new_with_value(10),
58
59     th = g_thread_create(test_decr_wait_thread, (gpointer)&data, TRUE, NULL);
60
61     /* sleep to give semaphore_decrement() a chance to block (or not). */
62     g_usleep(G_USEC_PER_SEC / 4);
63
64     /* and then increment the semaphore enough that the decrement can succeed */
65     data.increment_called = TRUE;
66     semaphore_increment(data.sem, 10);
67
68     /* join the thread and see how it fared. */
69     rv = GPOINTER_TO_INT(g_thread_join(th));
70
71     semaphore_free(data.sem);
72
73     return (rv == 1);
74 }
75
76
77 /*
78  * test that semaphore_wait_empty waits properly
79  */
80
81 static gpointer
82 test_wait_empty_thread(gpointer datap)
83 {
84     semaphore_t *sem = datap;
85
86     /* should block */
87     semaphore_decrement(sem, 20);
88
89     /* value should be 10 now (decremented from 30) */
90     if (sem->value != 10)
91         return GINT_TO_POINTER(1);
92
93     /* sleep for a bit */
94     g_usleep(G_USEC_PER_SEC / 4);
95
96     /* decrement those last 10, which should trigger the zero */
97     semaphore_decrement(sem, 10);
98
99     return GINT_TO_POINTER(0);
100 }
101
102 static gboolean
103 test_wait_empty(void)
104 {
105     GThread *th;
106     semaphore_t *sem = semaphore_new_with_value(10);
107     int rv;
108
109     th = g_thread_create(test_wait_empty_thread, (gpointer)sem, TRUE, NULL);
110
111     /* sleep to give semaphore_decrement() a chance to block (or not). */
112     g_usleep(G_USEC_PER_SEC / 4);
113
114     /* add another 10, so decrement can hit zero next time it's called */
115     semaphore_increment(sem, 10);
116
117     /* and wait on the semaphore emptying */
118     semaphore_wait_empty(sem);
119
120     /* join the thread and see how it fared. */
121     rv = GPOINTER_TO_INT(g_thread_join(th));
122
123     semaphore_free(sem);
124
125     return (rv == 1);
126 }
127
128 /*
129  * test that semaphore_force_adjust correctly wakes both
130  * semaphore_decrement and semaphore_wait_empty.
131  */
132
133 static gpointer
134 test_force_adjust_thread(gpointer datap)
135 {
136     semaphore_t *sem = datap;
137
138     /* this should block */
139     semaphore_decrement(sem, 20);
140
141     /* and this should block, too - it's fun */
142     semaphore_wait_empty(sem);
143
144     return NULL;
145 }
146
147 static gboolean
148 test_force_adjust(void)
149 {
150     GThread *th;
151     semaphore_t *sem = semaphore_new_with_value(10);
152
153     th = g_thread_create(test_force_adjust_thread, (gpointer)sem, TRUE, NULL);
154
155     /* sleep to give semaphore_decrement() a chance to block (or not). */
156     g_usleep(G_USEC_PER_SEC / 4);
157
158     /* add another 20, so decrement can proceed, but leave the value at 10 */
159     semaphore_force_adjust(sem, 20);
160
161     /* sleep to give semaphore_wait_empty() a chance to block (or not). */
162     g_usleep(G_USEC_PER_SEC / 4);
163
164     /* and empty out the semaphore */
165     semaphore_force_adjust(sem, -10);
166
167     g_thread_join(th);
168
169     semaphore_free(sem);
170
171     /* it we didn't hang yet, it's all good */
172     return TRUE;
173 }
174
175 /*
176  * test that semaphore_force_set correctly wakes both
177  * semaphore_decrement and semaphore_wait_empty.
178  */
179
180 static gpointer
181 test_force_set_thread(gpointer datap)
182 {
183     semaphore_t *sem = datap;
184
185     /* this should block */
186     semaphore_decrement(sem, 20);
187
188     /* and this should block, too - it's fun */
189     semaphore_wait_empty(sem);
190
191     return NULL;
192 }
193
194 static gboolean
195 test_force_set(void)
196 {
197     GThread *th;
198     semaphore_t *sem = semaphore_new_with_value(10);
199
200     th = g_thread_create(test_force_set_thread, (gpointer)sem, TRUE, NULL);
201
202     /* sleep to give semaphore_decrement() a chance to block (or not). */
203     g_usleep(G_USEC_PER_SEC / 4);
204
205     /* set it to 30, so decrement can proceed, but leave the value at 10 */
206     semaphore_force_set(sem, 30);
207
208     /* sleep to give semaphore_wait_empty() a chance to block (or not). */
209     g_usleep(G_USEC_PER_SEC / 4);
210
211     /* and empty out the semaphore */
212     semaphore_force_set(sem, 0);
213
214     g_thread_join(th);
215
216     semaphore_free(sem);
217
218     /* it we didn't hang yet, it's all good */
219     return TRUE;
220 }
221
222 /*
223  * Main loop
224  */
225
226 int
227 main(int argc, char **argv)
228 {
229 #if defined(G_THREADS_ENABLED) && !defined(G_THREADS_IMPL_NONE)
230     static TestUtilsTest tests[] = {
231         TU_TEST(test_decr_wait, 90),
232         TU_TEST(test_wait_empty, 90),
233         TU_TEST(test_force_adjust, 90),
234         TU_TEST(test_force_set, 90),
235         TU_END()
236     };
237
238     glib_init();
239
240     return testutils_run_tests(argc, argv, tests);
241 #else
242     g_fprintf(stderr, "No thread support on this platform -- nothing to test\n");
243     return 0;
244 #endif
245 }