]> git.saurik.com Git - apple/xnu.git/blame - tests/testposixshm.c
xnu-4903.270.47.tar.gz
[apple/xnu.git] / tests / testposixshm.c
CommitLineData
0a7de745
A
1#include <stdlib.h>
2#include <unistd.h>
3#include <sys/mman.h>
4#include <fcntl.h>
5#include <sys/types.h>
6#include <sys/sysctl.h>
7#include <stdatomic.h>
8#include <TargetConditionals.h>
9
10#include <darwintest.h>
11
12static int nthreads = 0;
13static int fd;
14static _Atomic int phase = 0;
15static _Atomic int pass_count = 0;
16static _Atomic int fail_count = 0;
17
18static void *
19worker_thread_func(__unused void *arg)
20{
21 int myfd;
22 int error;
23
24 /* test racing shm_open */
25 while (atomic_load(&phase) == 0) {
26 ;
27 }
28 myfd = shm_open("abcd", O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
29 if (myfd == -1) {
30 T_QUIET; T_EXPECT_EQ(errno, EEXIST, "Expected EEXIST");
31 atomic_fetch_add(&fail_count, 1);
32 } else {
33 fd = myfd;
34 atomic_fetch_add(&pass_count, 1);
35 }
36
37 /* test racing ftruncate */
38 while (atomic_load(&phase) == 1) {
39 ;
40 }
41 error = ftruncate(fd, 8 * 1024);
42 if (error == -1) {
43 T_QUIET; T_EXPECT_EQ(errno, EINVAL, "Expected EINVAL");
44 atomic_fetch_add(&fail_count, 1);
45 } else {
46 atomic_fetch_add(&pass_count, 1);
47 }
48
49 /* test racing close */
50 while (atomic_load(&phase) == 2) {
51 ;
52 }
53 error = close(fd);
54 if (error == -1) {
55 T_QUIET; T_EXPECT_EQ(errno, EBADF, "Expected EBADF");
56 atomic_fetch_add(&fail_count, 1);
57 } else {
58 atomic_fetch_add(&pass_count, 1);
59 }
60
61 /* test racing shm_unlink() */
62 while (atomic_load(&phase) == 3) {
63 ;
64 }
65 error = shm_unlink("abcd");
66 if (error == -1) {
67 T_QUIET; T_EXPECT_EQ(errno, ENOENT, "Expected ENOENT");
68 atomic_fetch_add(&fail_count, 1);
69 } else {
70 atomic_fetch_add(&pass_count, 1);
71 }
72 return NULL;
73}
74
75static void
76create_threads(void)
77{
78 int ret;
79 int ncpu;
80 size_t ncpu_size = sizeof(ncpu);
81 int i;
82 pthread_attr_t attr;
83
84 ret = sysctlbyname("hw.ncpu", &ncpu, &ncpu_size, NULL, 0);
85 T_ASSERT_POSIX_SUCCESS(ret, "sysctlbyname(hw.ncpu)");
86
87 T_QUIET; T_LOG("%s: Detected %d CPUs\n", __FUNCTION__, ncpu);
88
89 nthreads = ncpu;
90 T_QUIET; T_LOG("%s: Will create %d threads\n", __FUNCTION__, nthreads);
91
92 ret = pthread_attr_init(&attr);
93 T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "pthread_attr_init");
94
95 for (i = 0; i < nthreads; i++) {
96 pthread_t thread;
97 ret = pthread_create(&thread, &attr, worker_thread_func, NULL);
98 T_QUIET; T_ASSERT_POSIX_ZERO(ret, "pthread_create");
99 }
100}
101
102
103T_DECL(testposixshm, "Posix Shared Memory tests")
104{
105 int fd1;
106 int fd2;
107 int *addr;
108 char *noname = "";
109 char *toolong = "12345678901234567890123456789012";
110 char *maxname = "1234567890123456789012345678901";
111
112 /* must have O_CREAT */
113 fd1 = shm_open(maxname, O_RDWR, S_IRUSR | S_IWUSR);
114 T_EXPECT_EQ(fd1, -1, "shm_open() missing O_CREAT");
115 T_WITH_ERRNO;
116 T_EXPECT_EQ(errno, ENOENT, "Expected ENOENT");
117
118 /* name too long */
119 fd1 = shm_open(toolong, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
120 T_EXPECT_EQ(fd1, -1, "shm_open() name too long");
121 T_WITH_ERRNO;
122 T_EXPECT_EQ(errno, ENAMETOOLONG, "Expected ENAMETOOLONG");
123
124 /* invalid name */
125 fd1 = shm_open(noname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
126 T_EXPECT_EQ(fd1, -1, "shm_open() invalid name");
127 T_WITH_ERRNO;
128 T_EXPECT_EQ(errno, EINVAL, "Expected EINVAL");
129
130 /* valid open */
131 fd1 = shm_open(maxname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
132 T_EXPECT_POSIX_SUCCESS(fd1, "valid shm_open() result");
133
134 /* O_CREAT, but not O_EXCL should work */
135 fd2 = shm_open(maxname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
136 T_EXPECT_POSIX_SUCCESS(fd2, "shm_open() no O_EXCL");
137
138 /* close should work */
139 T_EXPECT_POSIX_ZERO(close(fd2), "close()");
140
141 /* O_CREAT | O_EXCL should fail */
142 fd2 = shm_open(maxname, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
143 T_WITH_ERRNO;
144 T_EXPECT_EQ(fd2, -1, "shm_open() existing but O_EXCL");
145 T_EXPECT_EQ(errno, EEXIST, "Expected EEXIST");
146
147 /* use ftruncate to create the memory */
148 T_EXPECT_POSIX_ZERO(ftruncate(fd1, 16 * 1024), NULL);
149
150 /* a second ftruncate should fail */
151 T_WITH_ERRNO;
152 T_EXPECT_EQ(ftruncate(fd1, 8 * 1024), -1, "second ftruncate() should fail");
153 T_EXPECT_EQ(errno, EINVAL, "Expected EINVAL");
154
155 /* Map the memory object */
156 addr = mmap(0, 4 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd1, 0);
157 T_WITH_ERRNO;
158 T_EXPECT_NE((void *)addr, MAP_FAILED, "mmap() should work");
159
160 /* close should work */
161 T_EXPECT_POSIX_ZERO(close(fd1), "close()");
162
163 /* unlink should work */
164 T_EXPECT_POSIX_SUCCESS(shm_unlink(maxname), "shm_unlink()");
165
166 /* shm_open() after unlink/close should fail */
167 fd2 = shm_open(maxname, O_RDWR, S_IRUSR | S_IWUSR);
168 T_WITH_ERRNO;
169 T_EXPECT_EQ(fd2, -1, "shm_open() but removed");
170 T_EXPECT_EQ(errno, ENOENT, "Expected ENOENT");
171
172 /*
173 * second phase of tests, try to create race conditions for
174 * shm_open() - multiple threads do shm_open(, ... O_EXCL, ...)
175 * ftruncate() - multiple threads, only 1 should succeed.
176 * fclose() - multiple threads, only 1 should succeed.
177 * shm_unlink() - multiple threads, only 1 should succeed.
178 */
179 create_threads();
180 sleep(1);
181 T_LOG("Race testing shm_open");
182 atomic_fetch_add(&phase, 1);
183 while (pass_count + fail_count < nthreads) {
184 sleep(1);
185 }
186 T_EXPECT_EQ(pass_count, 1, "racing shm_open()");
187 T_EXPECT_EQ(fail_count, nthreads - 1, "racing shm_open()");
188
189 atomic_store(&pass_count, 0);
190 atomic_store(&fail_count, 0);
191 T_LOG("Race testing ftruncate\n");
192 atomic_fetch_add(&phase, 1);
193 while (pass_count + fail_count < nthreads) {
194 sleep(1);
195 }
196 T_EXPECT_EQ(pass_count, 1, "racing ftruncate()");
197 T_EXPECT_EQ(fail_count, nthreads - 1, "racing ftruncate()");
198
199 atomic_store(&pass_count, 0);
200 atomic_store(&fail_count, 0);
201 T_LOG("Race testing fclose\n");
202 atomic_fetch_add(&phase, 1);
203 while (pass_count + fail_count < nthreads) {
204 sleep(1);
205 }
206 T_EXPECT_EQ(pass_count, 1, "racing fclose()");
207 T_EXPECT_EQ(fail_count, nthreads - 1, "racing fclose()");
208
209 atomic_store(&pass_count, 0);
210 atomic_store(&fail_count, 0);
211 T_LOG("Race testing shm_unlink\n");
212 atomic_fetch_add(&phase, 1);
213 while (pass_count + fail_count < nthreads) {
214 sleep(1);
215 }
216 T_EXPECT_EQ(pass_count, 1, "racing shm_unlink()");
217 T_EXPECT_EQ(fail_count, nthreads - 1, "racing shm_unlink()");
218}