Imported Upstream version 3.3.3
[debian/amanda] / common-src / amsemaphore-test.c
1 /*
2  * Copyright (c) 2008-2012 Zmanda, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17  *
18  * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
19  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
20  */
21
22 #include "amanda.h"
23 #include "amsemaphore.h"
24 #include "testutils.h"
25 #include "util.h"
26
27 /*
28  * test that decrement waits properly
29  */
30
31 struct test_decr_wait_data {
32     amsemaphore_t *sem;
33     gboolean increment_called;
34 };
35
36 static gpointer
37 test_decr_wait_thread(gpointer datap)
38 {
39     struct test_decr_wait_data *data = datap;
40
41     /* should block */
42     amsemaphore_decrement(data->sem, 20);
43
44     /* if increment hasn't been called yet, that's an error. */
45     if (!data->increment_called)
46         return GINT_TO_POINTER(0);
47
48     return GINT_TO_POINTER(1);
49 }
50
51 static gboolean
52 test_decr_wait(void)
53 {
54     GThread *th;
55     struct test_decr_wait_data data = { NULL, FALSE };
56     int rv;
57
58     data.sem = amsemaphore_new_with_value(10),
59
60     th = g_thread_create(test_decr_wait_thread, (gpointer)&data, TRUE, NULL);
61
62     /* sleep to give amsemaphore_decrement() a chance to block (or not). */
63     g_usleep(G_USEC_PER_SEC / 4);
64
65     /* and then increment the semaphore enough that the decrement can succeed */
66     data.increment_called = TRUE;
67     amsemaphore_increment(data.sem, 10);
68
69     /* join the thread and see how it fared. */
70     rv = GPOINTER_TO_INT(g_thread_join(th));
71
72     amsemaphore_free(data.sem);
73
74     return (rv == 1);
75 }
76
77
78 /*
79  * test that amsemaphore_wait_empty waits properly
80  */
81
82 static gpointer
83 test_wait_empty_thread(gpointer datap)
84 {
85     amsemaphore_t *sem = datap;
86
87     /* should block */
88     amsemaphore_decrement(sem, 20);
89
90     /* value should be 10 now (decremented from 30) */
91     if (sem->value != 10)
92         return GINT_TO_POINTER(1);
93
94     /* sleep for a bit */
95     g_usleep(G_USEC_PER_SEC / 4);
96
97     /* decrement those last 10, which should trigger the zero */
98     amsemaphore_decrement(sem, 10);
99
100     return GINT_TO_POINTER(0);
101 }
102
103 static gboolean
104 test_wait_empty(void)
105 {
106     GThread *th;
107     amsemaphore_t *sem = amsemaphore_new_with_value(10);
108     int rv;
109
110     th = g_thread_create(test_wait_empty_thread, (gpointer)sem, TRUE, NULL);
111
112     /* sleep to give amsemaphore_decrement() a chance to block (or not). */
113     g_usleep(G_USEC_PER_SEC / 4);
114
115     /* add another 10, so decrement can hit zero next time it's called */
116     amsemaphore_increment(sem, 10);
117
118     /* and wait on the semaphore emptying */
119     amsemaphore_wait_empty(sem);
120
121     /* join the thread and see how it fared. */
122     rv = GPOINTER_TO_INT(g_thread_join(th));
123
124     amsemaphore_free(sem);
125
126     return (rv == 1);
127 }
128
129 /*
130  * test that amsemaphore_force_adjust correctly wakes both
131  * amsemaphore_decrement and amsemaphore_wait_empty.
132  */
133
134 static gpointer
135 test_force_adjust_thread(gpointer datap)
136 {
137     amsemaphore_t *sem = datap;
138
139     /* this should block */
140     amsemaphore_decrement(sem, 20);
141
142     /* and this should block, too - it's fun */
143     amsemaphore_wait_empty(sem);
144
145     return NULL;
146 }
147
148 static gboolean
149 test_force_adjust(void)
150 {
151     GThread *th;
152     amsemaphore_t *sem = amsemaphore_new_with_value(10);
153
154     th = g_thread_create(test_force_adjust_thread, (gpointer)sem, TRUE, NULL);
155
156     /* sleep to give amsemaphore_decrement() a chance to block (or not). */
157     g_usleep(G_USEC_PER_SEC / 4);
158
159     /* add another 20, so decrement can proceed, but leave the value at 10 */
160     amsemaphore_force_adjust(sem, 20);
161
162     /* sleep to give amsemaphore_wait_empty() a chance to block (or not). */
163     g_usleep(G_USEC_PER_SEC / 4);
164
165     /* and empty out the semaphore */
166     amsemaphore_force_adjust(sem, -10);
167
168     g_thread_join(th);
169
170     amsemaphore_free(sem);
171
172     /* it we didn't hang yet, it's all good */
173     return TRUE;
174 }
175
176 /*
177  * test that amsemaphore_force_set correctly wakes both
178  * amsemaphore_decrement and amsemaphore_wait_empty.
179  */
180
181 static gpointer
182 test_force_set_thread(gpointer datap)
183 {
184     amsemaphore_t *sem = datap;
185
186     /* this should block */
187     amsemaphore_decrement(sem, 20);
188
189     /* and this should block, too - it's fun */
190     amsemaphore_wait_empty(sem);
191
192     return NULL;
193 }
194
195 static gboolean
196 test_force_set(void)
197 {
198     GThread *th;
199     amsemaphore_t *sem = amsemaphore_new_with_value(10);
200
201     th = g_thread_create(test_force_set_thread, (gpointer)sem, TRUE, NULL);
202
203     /* sleep to give amsemaphore_decrement() a chance to block (or not). */
204     g_usleep(G_USEC_PER_SEC / 4);
205
206     /* set it to 30, so decrement can proceed, but leave the value at 10 */
207     amsemaphore_force_set(sem, 30);
208
209     /* sleep to give amsemaphore_wait_empty() a chance to block (or not). */
210     g_usleep(G_USEC_PER_SEC / 4);
211
212     /* and empty out the semaphore */
213     amsemaphore_force_set(sem, 0);
214
215     g_thread_join(th);
216
217     amsemaphore_free(sem);
218
219     /* it we didn't hang yet, it's all good */
220     return TRUE;
221 }
222
223 /*
224  * Main loop
225  */
226
227 int
228 main(int argc, char **argv)
229 {
230 #if defined(G_THREADS_ENABLED) && !defined(G_THREADS_IMPL_NONE)
231     static TestUtilsTest tests[] = {
232         TU_TEST(test_decr_wait, 90),
233         TU_TEST(test_wait_empty, 90),
234         TU_TEST(test_force_adjust, 90),
235         TU_TEST(test_force_set, 90),
236         TU_END()
237     };
238
239     glib_init();
240
241     return testutils_run_tests(argc, argv, tests);
242 #else
243     g_fprintf(stderr, "No thread support on this platform -- nothing to test\n");
244     return 0;
245 #endif
246 }