1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "testutil.h"
18 #include "apr_shm.h"
19 #include "apr_errno.h"
20 #include "apr_general.h"
21 #include "apr_lib.h"
22 #include "apr_strings.h"
23 #include "apr_thread_proc.h"
24 #include "apr_time.h"
25 #include "testshm.h"
26 #include "apr.h"
27
28 #if APR_HAVE_STDLIB_H
29 #include <stdlib.h>
30 #endif
31
32 #if APR_HAS_SHARED_MEMORY
33
34 #if APR_HAS_FORK
msgwait(int sleep_sec,int first_box,int last_box)35 static int msgwait(int sleep_sec, int first_box, int last_box)
36 {
37 int i;
38 int recvd = 0;
39 apr_time_t start = apr_time_now();
40 apr_interval_time_t sleep_duration = apr_time_from_sec(sleep_sec);
41 while (apr_time_now() - start < sleep_duration) {
42 for (i = first_box; i < last_box; i++) {
43 if (boxes[i].msgavail && !strcmp(boxes[i].msg, MSG)) {
44 recvd++;
45 boxes[i].msgavail = 0; /* reset back to 0 */
46 /* reset the msg field. 1024 is a magic number and it should
47 * be a macro, but I am being lazy.
48 */
49 memset(boxes[i].msg, 0, 1024);
50 }
51 }
52 apr_sleep(apr_time_make(0, 10000)); /* 10ms */
53 }
54 return recvd;
55 }
56
msgput(int boxnum,char * msg)57 static void msgput(int boxnum, char *msg)
58 {
59 apr_cpystrn(boxes[boxnum].msg, msg, strlen(msg) + 1);
60 boxes[boxnum].msgavail = 1;
61 }
62 #endif /* APR_HAS_FORK */
63
test_anon_create(abts_case * tc,void * data)64 static void test_anon_create(abts_case *tc, void *data)
65 {
66 apr_status_t rv;
67 apr_shm_t *shm = NULL;
68
69 rv = apr_shm_create(&shm, SHARED_SIZE, NULL, p);
70 APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv);
71 ABTS_PTR_NOTNULL(tc, shm);
72
73 rv = apr_shm_destroy(shm);
74 APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv);
75 }
76
test_check_size(abts_case * tc,void * data)77 static void test_check_size(abts_case *tc, void *data)
78 {
79 apr_status_t rv;
80 apr_shm_t *shm = NULL;
81 apr_size_t retsize;
82
83 rv = apr_shm_create(&shm, SHARED_SIZE, NULL, p);
84 APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv);
85 ABTS_PTR_NOTNULL(tc, shm);
86
87 retsize = apr_shm_size_get(shm);
88 ABTS_SIZE_EQUAL(tc, SHARED_SIZE, retsize);
89
90 rv = apr_shm_destroy(shm);
91 APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv);
92 }
93
test_shm_allocate(abts_case * tc,void * data)94 static void test_shm_allocate(abts_case *tc, void *data)
95 {
96 apr_status_t rv;
97 apr_shm_t *shm = NULL;
98
99 rv = apr_shm_create(&shm, SHARED_SIZE, NULL, p);
100 APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv);
101 ABTS_PTR_NOTNULL(tc, shm);
102
103 boxes = apr_shm_baseaddr_get(shm);
104 ABTS_PTR_NOTNULL(tc, boxes);
105
106 rv = apr_shm_destroy(shm);
107 APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv);
108 }
109
110 #if APR_HAS_FORK
test_anon(abts_case * tc,void * data)111 static void test_anon(abts_case *tc, void *data)
112 {
113 apr_proc_t proc;
114 apr_status_t rv;
115 apr_shm_t *shm;
116 apr_size_t retsize;
117 int cnt, i;
118 int recvd;
119
120 rv = apr_shm_create(&shm, SHARED_SIZE, NULL, p);
121 APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv);
122 ABTS_PTR_NOTNULL(tc, shm);
123
124 retsize = apr_shm_size_get(shm);
125 ABTS_INT_EQUAL(tc, SHARED_SIZE, retsize);
126
127 boxes = apr_shm_baseaddr_get(shm);
128 ABTS_PTR_NOTNULL(tc, boxes);
129
130 rv = apr_proc_fork(&proc, p);
131 if (rv == APR_INCHILD) { /* child */
132 int num = msgwait(5, 0, N_BOXES);
133 /* exit with the number of messages received so that the parent
134 * can check that all messages were received.
135 */
136 exit(num);
137 }
138 else if (rv == APR_INPARENT) { /* parent */
139 i = N_BOXES;
140 cnt = 0;
141 while (cnt++ < N_MESSAGES) {
142 if ((i-=3) < 0) {
143 i += N_BOXES; /* start over at the top */
144 }
145 msgput(i, MSG);
146 apr_sleep(apr_time_make(0, 10000));
147 }
148 }
149 else {
150 ABTS_FAIL(tc, "apr_proc_fork failed");
151 }
152 /* wait for the child */
153 rv = apr_proc_wait(&proc, &recvd, NULL, APR_WAIT);
154 ABTS_INT_EQUAL(tc, N_MESSAGES, recvd);
155
156 rv = apr_shm_destroy(shm);
157 APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv);
158 }
159 #endif
160
test_named(abts_case * tc,void * data)161 static void test_named(abts_case *tc, void *data)
162 {
163 apr_status_t rv;
164 apr_shm_t *shm = NULL;
165 apr_size_t retsize;
166 apr_proc_t pidproducer, pidconsumer;
167 apr_procattr_t *attr1 = NULL, *attr2 = NULL;
168 int sent, received;
169 apr_exit_why_e why;
170 const char *args[4];
171
172 apr_shm_remove(SHARED_FILENAME, p);
173
174 rv = apr_shm_create(&shm, SHARED_SIZE, SHARED_FILENAME, p);
175 APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv);
176 if (rv != APR_SUCCESS) {
177 return;
178 }
179 ABTS_PTR_NOTNULL(tc, shm);
180
181 retsize = apr_shm_size_get(shm);
182 ABTS_SIZE_EQUAL(tc, SHARED_SIZE, retsize);
183
184 boxes = apr_shm_baseaddr_get(shm);
185 ABTS_PTR_NOTNULL(tc, boxes);
186
187 rv = apr_procattr_create(&attr1, p);
188 ABTS_PTR_NOTNULL(tc, attr1);
189 APR_ASSERT_SUCCESS(tc, "Couldn't create attr1", rv);
190
191 rv = apr_procattr_cmdtype_set(attr1, APR_PROGRAM_ENV);
192 APR_ASSERT_SUCCESS(tc, "Couldn't set copy environment", rv);
193
194 args[0] = apr_pstrdup(p, "testshmproducer" EXTENSION);
195 args[1] = NULL;
196 rv = apr_proc_create(&pidproducer, TESTBINPATH "testshmproducer" EXTENSION, args,
197 NULL, attr1, p);
198 APR_ASSERT_SUCCESS(tc, "Couldn't launch producer", rv);
199
200 rv = apr_procattr_create(&attr2, p);
201 ABTS_PTR_NOTNULL(tc, attr2);
202 APR_ASSERT_SUCCESS(tc, "Couldn't create attr2", rv);
203
204 rv = apr_procattr_cmdtype_set(attr2, APR_PROGRAM_ENV);
205 APR_ASSERT_SUCCESS(tc, "Couldn't set copy environment", rv);
206
207 args[0] = apr_pstrdup(p, "testshmconsumer" EXTENSION);
208 rv = apr_proc_create(&pidconsumer, TESTBINPATH "testshmconsumer" EXTENSION, args,
209 NULL, attr2, p);
210 APR_ASSERT_SUCCESS(tc, "Couldn't launch consumer", rv);
211
212 rv = apr_proc_wait(&pidconsumer, &received, &why, APR_WAIT);
213 ABTS_INT_EQUAL(tc, APR_CHILD_DONE, rv);
214 ABTS_INT_EQUAL(tc, APR_PROC_EXIT, why);
215
216 rv = apr_proc_wait(&pidproducer, &sent, &why, APR_WAIT);
217 ABTS_INT_EQUAL(tc, APR_CHILD_DONE, rv);
218 ABTS_INT_EQUAL(tc, APR_PROC_EXIT, why);
219
220 /* Cleanup before testing that producer and consumer worked correctly.
221 * This way, if they didn't succeed, we can just run this test again
222 * without having to cleanup manually.
223 */
224 APR_ASSERT_SUCCESS(tc, "Error destroying shared memory",
225 apr_shm_destroy(shm));
226
227 ABTS_INT_EQUAL(tc, sent, received);
228
229 }
230
test_named_remove(abts_case * tc,void * data)231 static void test_named_remove(abts_case *tc, void *data)
232 {
233 apr_status_t rv;
234 apr_shm_t *shm, *shm2;
235
236 apr_shm_remove(SHARED_FILENAME, p);
237
238 rv = apr_shm_create(&shm, SHARED_SIZE, SHARED_FILENAME, p);
239 APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv);
240 if (rv != APR_SUCCESS) {
241 return;
242 }
243 ABTS_PTR_NOTNULL(tc, shm);
244
245 rv = apr_shm_remove(SHARED_FILENAME, p);
246
247 /* On platforms which acknowledge the removal of the shared resource,
248 * ensure another of the same name may be created after removal;
249 */
250 if (rv == APR_SUCCESS)
251 {
252 rv = apr_shm_create(&shm2, SHARED_SIZE, SHARED_FILENAME, p);
253 APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv);
254 if (rv != APR_SUCCESS) {
255 return;
256 }
257 ABTS_PTR_NOTNULL(tc, shm2);
258
259 rv = apr_shm_destroy(shm2);
260 APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv);
261 }
262
263 rv = apr_shm_destroy(shm);
264 APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv);
265
266 /* Now ensure no named resource remains which we may attach to */
267 rv = apr_shm_attach(&shm, SHARED_FILENAME, p);
268 ABTS_TRUE(tc, rv != 0);
269 }
270
271 #endif
272
testshm(abts_suite * suite)273 abts_suite *testshm(abts_suite *suite)
274 {
275 suite = ADD_SUITE(suite)
276
277 #if APR_HAS_SHARED_MEMORY
278 abts_run_test(suite, test_anon_create, NULL);
279 abts_run_test(suite, test_check_size, NULL);
280 abts_run_test(suite, test_shm_allocate, NULL);
281 #if APR_HAS_FORK
282 abts_run_test(suite, test_anon, NULL);
283 #endif
284 abts_run_test(suite, test_named, NULL);
285 abts_run_test(suite, test_named_remove, NULL);
286 #endif
287
288 return suite;
289 }
290
291
292