]>
Commit | Line | Data |
---|---|---|
2546420a A |
1 | #include <assert.h> |
2 | #include <stdio.h> | |
3 | #include <unistd.h> | |
4 | #include <errno.h> | |
5 | #include <pthread.h> | |
6 | #include <stdlib.h> | |
7 | ||
8 | #include <darwintest.h> | |
9 | ||
10 | struct ctx { | |
11 | volatile int last_holder; | |
12 | volatile int quit; | |
13 | int iterations[2]; | |
14 | pthread_mutex_t l; | |
15 | }; | |
16 | ||
17 | static void * | |
18 | job(struct ctx *ctx, int idx) | |
19 | { | |
20 | int ret; | |
21 | while (!ctx->quit) { | |
22 | ret = pthread_mutex_trylock(&ctx->l); | |
23 | T_QUIET; T_ASSERT_TRUE(ret == EBUSY || ret == 0, "trylock"); | |
24 | ||
25 | if (ret == EBUSY) { | |
26 | T_QUIET; T_ASSERT_POSIX_ZERO(pthread_mutex_lock(&ctx->l), | |
27 | "pthread_mutex_lock"); | |
28 | // we know that the other thread was just holding the lock | |
29 | T_QUIET; T_ASSERT_EQ(ctx->last_holder, !idx, | |
30 | "expecting oppsosite last holder after failed trylock"); | |
31 | } | |
32 | ||
33 | ctx->last_holder = idx; | |
34 | ctx->iterations[idx]++; | |
35 | ||
36 | T_QUIET; T_ASSERT_POSIX_ZERO(pthread_mutex_unlock(&ctx->l), | |
37 | "pthread_mutex_unlock"); | |
38 | } | |
39 | return NULL; | |
40 | } | |
41 | ||
42 | static void * | |
43 | job1(void *ctx) | |
44 | { | |
45 | return job((struct ctx *)ctx, 0); | |
46 | } | |
47 | ||
48 | static void * | |
49 | job2(void *ctx) | |
50 | { | |
51 | return job((struct ctx *)ctx, 1); | |
52 | } | |
53 | ||
54 | T_DECL(mutex_trylock, "pthread_mutex_trylock", | |
55 | T_META_ALL_VALID_ARCHS(YES)) | |
56 | { | |
57 | // This testcase spins up two threads with identical jobs. They try-lock | |
58 | // the same mutex. If that fails, they check that the last holder of the | |
59 | // lock is the other thread. | |
60 | const int test_duration = 10; // sec | |
61 | struct ctx ctx = {0}; | |
62 | ||
63 | pthread_t t1, t2; | |
64 | ||
65 | T_ASSERT_POSIX_ZERO(pthread_mutex_init(&ctx.l, NULL), | |
66 | "pthread_mutex_init"); | |
67 | T_ASSERT_POSIX_ZERO(pthread_create(&t1, NULL, job1, &ctx), | |
68 | "pthread_create 1"); | |
69 | T_ASSERT_POSIX_ZERO(pthread_create(&t2, NULL, job2, &ctx), | |
70 | "pthread_create 2"); | |
71 | ||
72 | sleep(test_duration); | |
73 | ||
74 | ctx.quit = 1; | |
75 | T_ASSERT_POSIX_ZERO(pthread_join(t1, NULL), "pthread join 1"); | |
76 | T_ASSERT_POSIX_ZERO(pthread_join(t2, NULL), "pthread join 2"); | |
77 | ||
78 | T_LOG("after %d seconds iterations 0: %d, 1: %d. Exiting\n", | |
79 | test_duration, ctx.iterations[0], ctx.iterations[1]); | |
80 | } |