]> git.proxmox.com Git - mirror_lxc.git/blame - src/tests/locktests.c
Merge the liblxc API work by Serge Hallyn.
[mirror_lxc.git] / src / tests / locktests.c
CommitLineData
72d0e1cb
SG
1/* liblxcapi
2 *
3 * Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
4 * Copyright © 2012 Canonical Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19#include "../lxc/lxclock.h"
20#include <unistd.h>
21#include <signal.h>
22#include <stdio.h>
23#include <sys/types.h>
24#include <sys/wait.h>
25#include <stdlib.h>
26
27#define mycontainername "lxctest.sem"
28#define TIMEOUT_SECS 3
29
30int timedout;
31int pid_to_kill;
32
33void timeouthandler(int sig)
34{
35 // timeout received
36 timedout = 1;
37 kill(pid_to_kill, SIGTERM);
38}
39
40void starttimer(int secs)
41{
42 timedout = 0;
43 signal(SIGALRM, timeouthandler);
44 alarm(secs);
45}
46void stoptimer(void)
47{
48 alarm(0);
49 signal(SIGALRM, NULL);
50}
51
52int test_one_lock(sem_t *lock)
53{
54 int ret;
55 starttimer(TIMEOUT_SECS);
56 ret = lxclock(lock, TIMEOUT_SECS*2);
57 stoptimer();
58 if (ret == 0) {
59 lxcunlock(lock);
60 return 0;
61 }
62 if (timedout)
63 fprintf(stderr, "%d: timed out waiting for lock\n", __LINE__);
64 else
65 fprintf(stderr, "%d: failed to get single lock\n", __LINE__);
66 return 1;
67}
68
69/*
70 * get one lock. Fork a second task to try to get a second lock,
71 * with infinite timeout. If our alarm hits, kill the second
72 * task. If second task does not
73 */
74int test_two_locks(sem_t *lock)
75{
76 int status;
77 int ret;
78
79 ret = lxclock(lock, 1);
80 if (ret) {
81 fprintf(stderr, "%d: Error getting first lock\n", __LINE__);
82 return 2;
83 }
84
85 pid_to_kill = fork();
86 if (pid_to_kill < 0) {
87 fprintf(stderr, "%d: Failed to fork\n", __LINE__);
88 lxcunlock(lock);
89 return 3;
90 }
91
92 if (pid_to_kill == 0) { // child
93 ret = lxclock(lock, TIMEOUT_SECS*2);
94 if (ret == 0) {
95 lxcunlock(lock);
96 exit(0);
97 }
98 fprintf(stderr, "%d: child, was not able to get lock\n", __LINE__);
99 exit(1);
100 }
101 starttimer(TIMEOUT_SECS);
102 waitpid(pid_to_kill, &status, 0);
103 stoptimer();
104 if (WIFEXITED(status)) {
105 // child exited normally - timeout didn't kill it
106 if (WEXITSTATUS(status) == 0)
107 fprintf(stderr, "%d: child was able to get the lock\n", __LINE__);
108 else
109 fprintf(stderr, "%d: child timed out too early\n", __LINE__);
110 lxcunlock(lock);
111 return 1;
112 }
113 lxcunlock(lock);
114 return 0;
115}
116
117/*
118 * get one lock. try to get second lock, but asking for timeout. If
119 * should return failure. If our own alarm, set at twice the lock
120 * request's timeout, hits, then lxclock() did not properly time out.
121 */
122int test_with_timeout(sem_t *lock)
123{
124 int status;
125 int ret = 0;
126
127 ret = lxclock(lock, 0);
128 if (ret) {
129 fprintf(stderr, "%d: Error getting first lock\n", __LINE__);
130 return 2;
131 }
132 pid_to_kill = fork();
133 if (pid_to_kill < 0) {
134 fprintf(stderr, "%d: Error on fork\n", __LINE__);
135 lxcunlock(lock);
136 return 2;
137 }
138 if (pid_to_kill == 0) {
139 ret = lxclock(lock, TIMEOUT_SECS);
140 if (ret == 0) {
141 lxcunlock(lock);
142 exit(0);
143 }
144 exit(1);
145 }
146 starttimer(TIMEOUT_SECS * 2);
147 waitpid(pid_to_kill, &status, 0);
148 stoptimer();
149 if (!WIFEXITED(status)) {
150 fprintf(stderr, "%d: lxclock did not honor its timeout\n", __LINE__);
151 lxcunlock(lock);
152 return 1;
153 }
154 if (WEXITSTATUS(status) == 0) {
155 fprintf(stderr, "%d: child was able to get lock, should have failed with timeout\n", __LINE__);
156 ret = 1;
157 }
158 lxcunlock(lock);
159 return ret;
160}
161
162int main(int argc, char *argv[])
163{
164 int ret, sval, r;
165 sem_t *lock;
166
167 lock = lxc_newlock(NULL);
168 if (!lock) {
169 fprintf(stderr, "%d: failed to get unnamed lock\n", __LINE__);
170 exit(1);
171 }
172 ret = lxclock(lock, 0);
173 if (ret) {
174 fprintf(stderr, "%d: failed to take unnamed lock (%d)\n", __LINE__, ret);
175 exit(1);
176 }
177
178 ret = lxcunlock(lock);
179 if (ret) {
180 fprintf(stderr, "%d: failed to put unnamed lock (%d)\n", __LINE__, ret);
181 exit(1);
182 }
183
184 sem_destroy(lock);
185 free(lock);
186
187 lock = lxc_newlock(mycontainername);
188 if (!lock) {
189 fprintf(stderr, "%d: failed to get lock\n", __LINE__);
190 exit(1);
191 }
192 r = sem_getvalue(lock, &sval);
193 if (!r) {
194 fprintf(stderr, "%d: sem value at start is %d\n", __LINE__, sval);
195 } else {
196 fprintf(stderr, "%d: failed to get initial value\n", __LINE__);
197 }
198
199 ret = test_one_lock(lock);
200 if (ret) {
201 fprintf(stderr, "%d: test failed\n", __LINE__);
202 goto out;
203 }
204 r = sem_getvalue(lock, &sval);
205 if (!r) {
206 fprintf(stderr, "%d: sem value is %d\n", __LINE__, sval);
207 } else {
208 fprintf(stderr, "%d: failed to get sem value\n", __LINE__);
209 }
210
211 ret = test_two_locks(lock);
212 if (ret) {
213 fprintf(stderr, "%d: test failed\n", __LINE__);
214 goto out;
215 }
216 r = sem_getvalue(lock, &sval);
217 if (!r) {
218 fprintf(stderr, "%d: sem value is %d\n", __LINE__, sval);
219 } else {
220 fprintf(stderr, "%d: failed to get value\n", __LINE__);
221 }
222
223 ret = test_with_timeout(lock);
224 if (ret) {
225 fprintf(stderr, "%d: test failed\n", __LINE__);
226 goto out;
227 }
228 r = sem_getvalue(lock, &sval);
229 if (!r) {
230 fprintf(stderr, "%d: sem value is %d\n", __LINE__, sval);
231 } else {
232 fprintf(stderr, "%d: failed to get value\n", __LINE__);
233 }
234
235 fprintf(stderr, "all tests passed\n");
236
237out:
238 exit(ret);
239}