master
c 536 lines 12.2 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 flock.c
8
9 Abstract:
10
11 This file is a flock test.
12
13 --*/
14
15 #include "lxtcommon.h"
16 #include "unittests.h"
17 #include <sys/file.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <signal.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27
28 #define LXT_NAME "Flock"
29
30 int FnctlLockingVariation0(PLXT_ARGS Args);
31
32 int FlockVariation0(PLXT_ARGS Args);
33
34 //
35 // Global constants
36 //
37
38 static const LXT_VARIATION g_LxtVariations[] = {{"Flock", FlockVariation0}, {"Fcntl Locking", FnctlLockingVariation0}};
39
40 int FlockTestEntry(int Argc, char* Argv[])
41
42 /*++
43 --*/
44
45 {
46
47 LXT_ARGS Args;
48 int Result;
49
50 LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
51 LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
52
53 ErrorExit:
54 LxtUninitialize();
55 return !LXT_SUCCESS(Result);
56 }
57
58 int FnctlLockingVariation0(PLXT_ARGS Args)
59
60 /*++
61
62 Routine Description:
63
64 This routine tests file locking through the FCNTL system call.
65
66 Arguments:
67
68 Args - Supplies a pointer to the test arguments.
69
70 Return Value:
71
72 0 on success, -1 on failure.
73
74 --*/
75
76 {
77
78 char Buffer[10];
79 char ByteAlignedBuffer[sizeof(struct flock) + sizeof(struct flock64)];
80 int ChildPid;
81 int FileDescriptor;
82 struct flock* LockDescriptor;
83 struct flock64* LockDescriptor64;
84 int Result;
85
86 FileDescriptor = -1;
87 ChildPid = -1;
88
89 //
90 // Initialize the file for this test.
91 //
92
93 LxtCheckErrno(FileDescriptor = open("/data/test/fcntl_lock_test.bin", O_RDWR | O_CREAT, S_IRWXU));
94
95 LxtCheckErrno(write(FileDescriptor, Buffer, 10));
96
97 //
98 // Set the lock descriptor.
99 //
100
101 memset(ByteAlignedBuffer, 0, sizeof(ByteAlignedBuffer));
102 LockDescriptor = (struct flock*)&ByteAlignedBuffer[1];
103 LockDescriptor->l_type = F_WRLCK;
104 LockDescriptor->l_whence = SEEK_SET;
105 LockDescriptor->l_start = 0;
106 LockDescriptor->l_len = 10;
107
108 //
109 // Get the current lock state.
110 //
111
112 LxtLogInfo("Fnctl locking - Checking that lock can be set.");
113 LxtCheckErrno(fcntl(FileDescriptor, F_GETLK, LockDescriptor));
114 LxtCheckEqual(LockDescriptor->l_type, F_UNLCK, "%x");
115
116 //
117 // Set the lock.
118 //
119
120 LxtLogInfo("Fcntl locking - Setting the read lock by the parent process");
121 memset(ByteAlignedBuffer, 0, sizeof(ByteAlignedBuffer));
122 LockDescriptor->l_type = F_RDLCK;
123 LxtCheckErrno(fcntl(FileDescriptor, F_SETLK, LockDescriptor));
124
125 //
126 // Now change the lock to be a write lock.
127 //
128
129 memset(ByteAlignedBuffer, 0, sizeof(ByteAlignedBuffer));
130 LockDescriptor64 = (struct flock64*)&ByteAlignedBuffer[1];
131 LockDescriptor64->l_type = F_WRLCK;
132 LockDescriptor64->l_whence = SEEK_SET;
133 LockDescriptor64->l_start = 0;
134 LockDescriptor64->l_len = 10;
135
136 //
137 // Set the lock.
138 //
139
140 LxtLogInfo("Fcntl locking - Setting the write lock with 64 bit set lock");
141 LxtCheckErrno(fcntl(FileDescriptor, F_SETLK64, LockDescriptor64));
142
143 //
144 // Fork the process.
145 //
146
147 LxtLogInfo("Creating child process to test the lock.");
148 LxtCheckErrno(ChildPid = fork());
149 if (ChildPid == 0)
150 {
151
152 //
153 // Ensure that the lock was correctly set before. The lock descriptor is
154 // correctly set from before. The test expects to see the lock type be
155 // changed to exclusive, WRLCK, though.
156 //
157
158 LxtLogInfo("Fcntl child locking - Reading lock type");
159 LxtCheckErrno(fcntl(FileDescriptor, F_GETLK, LockDescriptor));
160 LxtCheckEqual(LockDescriptor->l_type, F_WRLCK, "%X");
161
162 Result = LXT_RESULT_SUCCESS;
163 goto ErrorExit;
164 }
165
166 Result = LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS);
167
168 ErrorExit:
169 if (FileDescriptor != 0)
170 {
171 close(FileDescriptor);
172 }
173
174 if (ChildPid == 0)
175 {
176 _exit(Result);
177 }
178
179 return Result;
180 }
181
182 int FlockVariation0(PLXT_ARGS Args)
183
184 /*++
185 --*/
186
187 {
188 int Result;
189 int FileDescriptor1;
190 int FileDescriptor2;
191 int FileDescriptor3;
192 int DupedDescriptor;
193 int ChildPid;
194 int Index;
195
196 //
197 // Initialize locals.
198 //
199
200 FileDescriptor1 = -1;
201 FileDescriptor2 = -1;
202 FileDescriptor3 = -1;
203 DupedDescriptor = -1;
204 ChildPid = -1;
205
206 //
207 // Open a file that will be locked.
208 //
209
210 FileDescriptor1 = open("/data/test/flock_test.bin", O_RDWR | O_CREAT, S_IRWXU);
211
212 if (FileDescriptor1 == -1)
213 {
214 Result = errno;
215 LxtLogError("Could not create test file! %d", Result);
216 goto cleanup;
217 }
218
219 FileDescriptor2 = open("/data/test/flock_test.bin", O_RDWR | O_CREAT, S_IRWXU);
220
221 if (FileDescriptor2 == -1)
222 {
223 Result = errno;
224 LxtLogError("Could not create test file! %d", Result);
225 goto cleanup;
226 }
227
228 Result = flock(FileDescriptor1, LOCK_EX);
229
230 if (Result < 0)
231 {
232 Result = errno;
233 LxtLogError("Lock failed! %d", Result);
234 goto cleanup;
235 }
236
237 FileDescriptor3 = open("/data/test/flock_test.bin", O_RDWR | O_CREAT, S_IRWXU);
238
239 if (FileDescriptor3 == -1)
240 {
241 Result = errno;
242 LxtLogError("Could not create test file! %d", Result);
243 goto cleanup;
244 }
245
246 //
247 // Lock the file from another descriptor (non-blocking) and it should fail
248 // accordingly.
249 //
250
251 Result = flock(FileDescriptor2, LOCK_EX | LOCK_NB);
252
253 if (Result == 0)
254 {
255 Result = -1;
256 LxtLogError("Lock succeeded but should have failed!");
257 goto cleanup;
258 }
259
260 Result = errno;
261 if (Result != EWOULDBLOCK)
262 {
263 LxtLogError("Lock failed but with wrong error! %d", Result);
264 goto cleanup;
265 }
266
267 //
268 // Dupe the owner descriptor and lock the file shared. This should convert
269 // the file to shared.
270 //
271
272 DupedDescriptor = dup(FileDescriptor1);
273
274 if (DupedDescriptor < 0)
275 {
276 Result = errno;
277 LxtLogError("Could not dup the descriptor! %d", Result);
278 goto cleanup;
279 }
280
281 for (Index = 0; Index < 2; Index += 1)
282 {
283
284 Result = flock(DupedDescriptor, LOCK_EX);
285
286 if (Result < 0)
287 {
288 Result = errno;
289 LxtLogError("Lock exclusive conversion failed! %d", Result);
290 goto cleanup;
291 }
292
293 Result = flock(DupedDescriptor, LOCK_SH);
294
295 if (Result < 0)
296 {
297 Result = errno;
298 LxtLogError("Lock shared conversion failed! %d", Result);
299 goto cleanup;
300 }
301 }
302
303 //
304 // The lock is now owned shared by descriptor1 (via duped descriptor) so now
305 // descriptor 2 should be able to acquire it shared.
306 //
307
308 Result = flock(FileDescriptor2, LOCK_SH | LOCK_NB);
309
310 if (Result < 0)
311 {
312 Result = errno;
313 LxtLogError("Lock shared failed for descriptor2! %d", Result);
314 goto cleanup;
315 }
316
317 //
318 // Unlock via descriptor1. That leaves just descriptor2 shared.
319 //
320
321 Result = flock(FileDescriptor1, LOCK_UN);
322
323 if (Result < 0)
324 {
325 Result = errno;
326 LxtLogError("Unlock failed for descriptor1! %d", Result);
327 goto cleanup;
328 }
329
330 //
331 // Fork to create another thread to wait for lock.
332 //
333
334 for (Index = 0; Index < 2; Index += 1)
335 {
336
337 ChildPid = fork();
338
339 if (ChildPid == -1)
340 {
341 Result = errno;
342 LxtLogError("Fork failed! %d", Result);
343 goto cleanup;
344 }
345
346 if (ChildPid == 0)
347 {
348 int FileDescriptor;
349
350 if (Index == 0)
351 {
352 FileDescriptor = FileDescriptor1;
353 }
354 else
355 {
356 FileDescriptor = FileDescriptor3;
357 }
358
359 //
360 // Wait for exclusive lock.
361 //
362
363 close(FileDescriptor2);
364 FileDescriptor2 = -1;
365
366 LxtLogInfo("C%u: Waiting for lock on FileDescriptor...", Index);
367
368 Result = flock(FileDescriptor, LOCK_EX);
369
370 if (Result < 0)
371 {
372 Result = errno;
373 LxtLogError("Lock acquire failed for descriptor1! %d", Result);
374 goto cleanup;
375 }
376
377 LxtLogInfo("C%u: Lock acquired on FileDescriptor...", Index);
378
379 Result = flock(FileDescriptor, LOCK_UN);
380
381 if (Result < 0)
382 {
383 Result = errno;
384 LxtLogError("Unlock failed for descriptor1! %d", Result);
385 goto cleanup;
386 }
387
388 LxtLogInfo("C%u: Sleeping 3 secs...", Index);
389
390 usleep(3 * 1000 * 1000);
391
392 LxtLogInfo("C%u: Waiting for lock shared on FileDescriptor...", Index);
393
394 Result = flock(FileDescriptor, LOCK_SH);
395
396 if (Result < 0)
397 {
398 Result = errno;
399 LxtLogError("Lock acquire failed for descriptor1! %d", Result);
400 goto cleanup;
401 }
402
403 LxtLogInfo("C%u: Lock acquired on FileDescriptor...", Index);
404
405 Result = flock(FileDescriptor, LOCK_UN);
406
407 if (Result < 0)
408 {
409 Result = errno;
410 LxtLogError("Unlock failed for descriptor1! %d", Result);
411 goto cleanup;
412 }
413
414 if (Index == 0)
415 {
416 Result = LXT_RESULT_SUCCESS;
417 goto cleanup;
418 }
419
420 LxtLogInfo("C%u: Sleeping 3 secs...", Index);
421
422 usleep(3 * 1000 * 1000);
423
424 LxtLogInfo("C%u: Waiting for lock exclusive to be terminated...", Index);
425
426 Result = flock(FileDescriptor, LOCK_EX);
427
428 if (Result == 0)
429 {
430 Result = -1;
431 LxtLogError("Lock acquisition succeeded but EINTR expected!");
432 goto cleanup;
433 }
434
435 Result = errno;
436
437 if (Result != EINTR)
438 {
439 LxtLogError("Lock acquisition failed but not with EINTR! %d", Result);
440 goto cleanup;
441 }
442
443 Result = LXT_RESULT_SUCCESS;
444
445 goto cleanup;
446 }
447 }
448 LxtLogInfo("P: Waiting 3 seconds before releasing lock shared...");
449
450 usleep(3 * 1000 * 1000);
451
452 Result = flock(FileDescriptor2, LOCK_UN);
453
454 if (Result < 0)
455 {
456 Result = errno;
457 LxtLogError("Unlock failed for descriptor2! %d", Result);
458 goto cleanup;
459 }
460
461 usleep(1 * 1000 * 1000);
462
463 LxtLogInfo("P: Waiting to acquire lock exclusive...");
464
465 Result = flock(FileDescriptor2, LOCK_EX);
466
467 if (Result < 0)
468 {
469 Result = errno;
470 LxtLogError("Lock exclusive failed for descriptor2! %d", Result);
471 goto cleanup;
472 }
473
474 LxtLogInfo("P: Acquired lock exclusive.");
475
476 LxtLogInfo("P: Sleeping 5 secs...");
477
478 usleep(5 * 1000 * 1000);
479
480 LxtLogInfo("P: Releasing lock exclusive...");
481 Result = flock(FileDescriptor2, LOCK_UN);
482
483 if (Result < 0)
484 {
485 Result = errno;
486 LxtLogError("Unlock failed for descriptor2! %d", Result);
487 goto cleanup;
488 }
489
490 LxtLogInfo("P: Waiting to acquire lock shared...");
491
492 Result = flock(FileDescriptor2, LOCK_SH);
493
494 if (Result < 0)
495 {
496 Result = errno;
497 LxtLogError("Lock shared failed for descriptor2! %d", Result);
498 goto cleanup;
499 }
500
501 LxtLogInfo("P: Sleeping 5 secs...");
502
503 usleep(5 * 1000 * 1000);
504
505 //
506 // Force the child's file lock wait to be interrupted by a signal.
507 //
508
509 kill(ChildPid, SIGKILL);
510
511 Result = LXT_RESULT_SUCCESS;
512
513 cleanup:
514
515 if (FileDescriptor1 != -1)
516 {
517 close(FileDescriptor1);
518 }
519
520 if (FileDescriptor2 != -1)
521 {
522 close(FileDescriptor2);
523 }
524
525 if (DupedDescriptor != -1)
526 {
527 close(DupedDescriptor);
528 }
529
530 if (ChildPid == 0)
531 {
532 _exit(0);
533 }
534
535 return Result;
536 }