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 35static 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 57static 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 64static 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 77static 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 94static 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 111static 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 161static 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 231static 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 273abts_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