]>
git.saurik.com Git - apple/xnu.git/blob - tests/testposixshm.c
6 #include <sys/sysctl.h>
8 #include <TargetConditionals.h>
10 #include <darwintest.h>
12 static int nthreads
= 0;
14 static _Atomic
int phase
= 0;
15 static _Atomic
int pass_count
= 0;
16 static _Atomic
int fail_count
= 0;
19 worker_thread_func(__unused
void *arg
)
24 /* test racing shm_open */
25 while (atomic_load(&phase
) == 0) {
28 myfd
= shm_open("abcd", O_RDWR
| O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
);
30 T_QUIET
; T_EXPECT_EQ(errno
, EEXIST
, "Expected EEXIST");
31 atomic_fetch_add(&fail_count
, 1);
34 atomic_fetch_add(&pass_count
, 1);
37 /* test racing ftruncate */
38 while (atomic_load(&phase
) == 1) {
41 error
= ftruncate(fd
, 8 * 1024);
43 T_QUIET
; T_EXPECT_EQ(errno
, EINVAL
, "Expected EINVAL");
44 atomic_fetch_add(&fail_count
, 1);
46 atomic_fetch_add(&pass_count
, 1);
49 /* test racing close */
50 while (atomic_load(&phase
) == 2) {
55 T_QUIET
; T_EXPECT_EQ(errno
, EBADF
, "Expected EBADF");
56 atomic_fetch_add(&fail_count
, 1);
58 atomic_fetch_add(&pass_count
, 1);
61 /* test racing shm_unlink() */
62 while (atomic_load(&phase
) == 3) {
65 error
= shm_unlink("abcd");
67 T_QUIET
; T_EXPECT_EQ(errno
, ENOENT
, "Expected ENOENT");
68 atomic_fetch_add(&fail_count
, 1);
70 atomic_fetch_add(&pass_count
, 1);
80 size_t ncpu_size
= sizeof(ncpu
);
84 ret
= sysctlbyname("hw.ncpu", &ncpu
, &ncpu_size
, NULL
, 0);
85 T_ASSERT_POSIX_SUCCESS(ret
, "sysctlbyname(hw.ncpu)");
87 T_QUIET
; T_LOG("%s: Detected %d CPUs\n", __FUNCTION__
, ncpu
);
90 T_QUIET
; T_LOG("%s: Will create %d threads\n", __FUNCTION__
, nthreads
);
92 ret
= pthread_attr_init(&attr
);
93 T_QUIET
; T_ASSERT_MACH_SUCCESS(ret
, "pthread_attr_init");
95 for (i
= 0; i
< nthreads
; i
++) {
97 ret
= pthread_create(&thread
, &attr
, worker_thread_func
, NULL
);
98 T_QUIET
; T_ASSERT_POSIX_ZERO(ret
, "pthread_create");
103 T_DECL(testposixshm
, "Posix Shared Memory tests")
109 char *toolong
= "12345678901234567890123456789012";
110 char *maxname
= "1234567890123456789012345678901";
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");
116 T_EXPECT_EQ(errno
, ENOENT
, "Expected ENOENT");
119 fd1
= shm_open(toolong
, O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
);
120 T_EXPECT_EQ(fd1
, -1, "shm_open() name too long");
122 T_EXPECT_EQ(errno
, ENAMETOOLONG
, "Expected ENAMETOOLONG");
125 fd1
= shm_open(noname
, O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
);
126 T_EXPECT_EQ(fd1
, -1, "shm_open() invalid name");
128 T_EXPECT_EQ(errno
, EINVAL
, "Expected EINVAL");
131 fd1
= shm_open(maxname
, O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
);
132 T_EXPECT_POSIX_SUCCESS(fd1
, "valid shm_open() result");
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");
138 /* close should work */
139 T_EXPECT_POSIX_ZERO(close(fd2
), "close()");
141 /* O_CREAT | O_EXCL should fail */
142 fd2
= shm_open(maxname
, O_RDWR
| O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
);
144 T_EXPECT_EQ(fd2
, -1, "shm_open() existing but O_EXCL");
145 T_EXPECT_EQ(errno
, EEXIST
, "Expected EEXIST");
147 /* use ftruncate to create the memory */
148 T_EXPECT_POSIX_ZERO(ftruncate(fd1
, 16 * 1024), NULL
);
150 /* a second ftruncate should fail */
152 T_EXPECT_EQ(ftruncate(fd1
, 8 * 1024), -1, "second ftruncate() should fail");
153 T_EXPECT_EQ(errno
, EINVAL
, "Expected EINVAL");
155 /* Map the memory object */
156 addr
= mmap(0, 4 * 1024, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd1
, 0);
158 T_EXPECT_NE((void *)addr
, MAP_FAILED
, "mmap() should work");
160 /* close should work */
161 T_EXPECT_POSIX_ZERO(close(fd1
), "close()");
163 /* unlink should work */
164 T_EXPECT_POSIX_SUCCESS(shm_unlink(maxname
), "shm_unlink()");
166 /* shm_open() after unlink/close should fail */
167 fd2
= shm_open(maxname
, O_RDWR
, S_IRUSR
| S_IWUSR
);
169 T_EXPECT_EQ(fd2
, -1, "shm_open() but removed");
170 T_EXPECT_EQ(errno
, ENOENT
, "Expected ENOENT");
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.
181 T_LOG("Race testing shm_open");
182 atomic_fetch_add(&phase
, 1);
183 while (pass_count
+ fail_count
< nthreads
) {
186 T_EXPECT_EQ(pass_count
, 1, "racing shm_open()");
187 T_EXPECT_EQ(fail_count
, nthreads
- 1, "racing shm_open()");
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
) {
196 T_EXPECT_EQ(pass_count
, 1, "racing ftruncate()");
197 T_EXPECT_EQ(fail_count
, nthreads
- 1, "racing ftruncate()");
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
) {
206 T_EXPECT_EQ(pass_count
, 1, "racing fclose()");
207 T_EXPECT_EQ(fail_count
, nthreads
- 1, "racing fclose()");
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
) {
216 T_EXPECT_EQ(pass_count
, 1, "racing shm_unlink()");
217 T_EXPECT_EQ(fail_count
, nthreads
- 1, "racing shm_unlink()");