diff options
Diffstat (limited to 'test/testshm.c')
-rw-r--r-- | test/testshm.c | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/test/testshm.c b/test/testshm.c new file mode 100644 index 0000000..7387069 --- /dev/null +++ b/test/testshm.c @@ -0,0 +1,332 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "testutil.h" +#include "apr_shm.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_thread_proc.h" +#include "apr_time.h" +#include "testshm.h" +#include "apr.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#if APR_HAS_SHARED_MEMORY + +#if APR_HAS_FORK +static int msgwait(int sleep_sec, int first_box, int last_box) +{ + int i; + int recvd = 0; + apr_time_t start = apr_time_now(); + apr_interval_time_t sleep_duration = apr_time_from_sec(sleep_sec); + while (apr_time_now() - start < sleep_duration) { + for (i = first_box; i < last_box; i++) { + if (boxes[i].msgavail && !strcmp(boxes[i].msg, MSG)) { + recvd++; + boxes[i].msgavail = 0; /* reset back to 0 */ + /* reset the msg field. 1024 is a magic number and it should + * be a macro, but I am being lazy. + */ + memset(boxes[i].msg, 0, 1024); + } + } + apr_sleep(apr_time_make(0, 10000)); /* 10ms */ + } + return recvd; +} + +static void msgput(int boxnum, char *msg) +{ + apr_cpystrn(boxes[boxnum].msg, msg, strlen(msg) + 1); + boxes[boxnum].msgavail = 1; +} +#endif /* APR_HAS_FORK */ + +static void test_anon_create(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_shm_t *shm = NULL; + + rv = apr_shm_create(&shm, SHARED_SIZE, NULL, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + ABTS_PTR_NOTNULL(tc, shm); + + rv = apr_shm_destroy(shm); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); +} + +static void test_check_size(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_shm_t *shm = NULL; + apr_size_t retsize; + + rv = apr_shm_create(&shm, SHARED_SIZE, NULL, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + ABTS_PTR_NOTNULL(tc, shm); + + retsize = apr_shm_size_get(shm); + ABTS_SIZE_EQUAL(tc, SHARED_SIZE, retsize); + + rv = apr_shm_destroy(shm); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); +} + +static void test_shm_allocate(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_shm_t *shm = NULL; + + rv = apr_shm_create(&shm, SHARED_SIZE, NULL, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + ABTS_PTR_NOTNULL(tc, shm); + + boxes = apr_shm_baseaddr_get(shm); + ABTS_PTR_NOTNULL(tc, boxes); + + rv = apr_shm_destroy(shm); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); +} + +#if APR_HAS_FORK +static void test_anon(abts_case *tc, void *data) +{ + apr_proc_t proc; + apr_status_t rv; + apr_shm_t *shm; + apr_size_t retsize; + int cnt, i; + int recvd; + + rv = apr_shm_create(&shm, SHARED_SIZE, NULL, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + ABTS_PTR_NOTNULL(tc, shm); + + retsize = apr_shm_size_get(shm); + ABTS_INT_EQUAL(tc, SHARED_SIZE, retsize); + + boxes = apr_shm_baseaddr_get(shm); + ABTS_PTR_NOTNULL(tc, boxes); + + rv = apr_proc_fork(&proc, p); + if (rv == APR_INCHILD) { /* child */ + int num = msgwait(5, 0, N_BOXES); + /* exit with the number of messages received so that the parent + * can check that all messages were received. + */ + exit(num); + } + else if (rv == APR_INPARENT) { /* parent */ + i = N_BOXES; + cnt = 0; + while (cnt++ < N_MESSAGES) { + if ((i-=3) < 0) { + i += N_BOXES; /* start over at the top */ + } + msgput(i, MSG); + apr_sleep(apr_time_make(0, 10000)); + } + } + else { + ABTS_FAIL(tc, "apr_proc_fork failed"); + } + /* wait for the child */ + rv = apr_proc_wait(&proc, &recvd, NULL, APR_WAIT); + ABTS_INT_EQUAL(tc, N_MESSAGES, recvd); + + rv = apr_shm_destroy(shm); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); +} +#endif + +static void test_named(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_shm_t *shm = NULL; + apr_size_t retsize; + apr_proc_t pidproducer, pidconsumer; + apr_procattr_t *attr1 = NULL, *attr2 = NULL; + int sent, received; + apr_exit_why_e why; + const char *args[4]; + + apr_shm_remove(SHARED_FILENAME, p); + + rv = apr_shm_create(&shm, SHARED_SIZE, SHARED_FILENAME, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + if (rv != APR_SUCCESS) { + return; + } + ABTS_PTR_NOTNULL(tc, shm); + + retsize = apr_shm_size_get(shm); + ABTS_SIZE_EQUAL(tc, SHARED_SIZE, retsize); + + boxes = apr_shm_baseaddr_get(shm); + ABTS_PTR_NOTNULL(tc, boxes); + + rv = apr_procattr_create(&attr1, p); + ABTS_PTR_NOTNULL(tc, attr1); + APR_ASSERT_SUCCESS(tc, "Couldn't create attr1", rv); + + rv = apr_procattr_cmdtype_set(attr1, APR_PROGRAM_ENV); + APR_ASSERT_SUCCESS(tc, "Couldn't set copy environment", rv); + + args[0] = apr_pstrdup(p, "testshmproducer" EXTENSION); + args[1] = NULL; + rv = apr_proc_create(&pidproducer, TESTBINPATH "testshmproducer" EXTENSION, args, + NULL, attr1, p); + APR_ASSERT_SUCCESS(tc, "Couldn't launch producer", rv); + + rv = apr_procattr_create(&attr2, p); + ABTS_PTR_NOTNULL(tc, attr2); + APR_ASSERT_SUCCESS(tc, "Couldn't create attr2", rv); + + rv = apr_procattr_cmdtype_set(attr2, APR_PROGRAM_ENV); + APR_ASSERT_SUCCESS(tc, "Couldn't set copy environment", rv); + + args[0] = apr_pstrdup(p, "testshmconsumer" EXTENSION); + rv = apr_proc_create(&pidconsumer, TESTBINPATH "testshmconsumer" EXTENSION, args, + NULL, attr2, p); + APR_ASSERT_SUCCESS(tc, "Couldn't launch consumer", rv); + + rv = apr_proc_wait(&pidconsumer, &received, &why, APR_WAIT); + ABTS_INT_EQUAL(tc, APR_CHILD_DONE, rv); + ABTS_INT_EQUAL(tc, APR_PROC_EXIT, why); + + rv = apr_proc_wait(&pidproducer, &sent, &why, APR_WAIT); + ABTS_INT_EQUAL(tc, APR_CHILD_DONE, rv); + ABTS_INT_EQUAL(tc, APR_PROC_EXIT, why); + + /* Cleanup before testing that producer and consumer worked correctly. + * This way, if they didn't succeed, we can just run this test again + * without having to cleanup manually. + */ + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory", + apr_shm_destroy(shm)); + + ABTS_INT_EQUAL(tc, sent, received); + +} + +static void test_named_remove(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_shm_t *shm, *shm2; + + apr_shm_remove(SHARED_FILENAME, p); + + rv = apr_shm_create(&shm, SHARED_SIZE, SHARED_FILENAME, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + if (rv != APR_SUCCESS) { + return; + } + ABTS_PTR_NOTNULL(tc, shm); + + rv = apr_shm_remove(SHARED_FILENAME, p); + + /* On platforms which acknowledge the removal of the shared resource, + * ensure another of the same name may be created after removal; + */ + if (rv == APR_SUCCESS) + { + rv = apr_shm_create(&shm2, SHARED_SIZE, SHARED_FILENAME, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + if (rv != APR_SUCCESS) { + return; + } + ABTS_PTR_NOTNULL(tc, shm2); + + rv = apr_shm_destroy(shm2); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); + } + + rv = apr_shm_destroy(shm); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); + + /* Now ensure no named resource remains which we may attach to */ + rv = apr_shm_attach(&shm, SHARED_FILENAME, p); + ABTS_TRUE(tc, rv != 0); +} + +static void test_named_delete(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_shm_t *shm, *shm2; + + apr_shm_remove(SHARED_FILENAME, p); + + rv = apr_shm_create(&shm, SHARED_SIZE, SHARED_FILENAME, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + if (rv != APR_SUCCESS) { + return; + } + ABTS_PTR_NOTNULL(tc, shm); + + rv = apr_shm_delete(shm); + + /* On platforms which acknowledge the removal of the shared resource, + * ensure another of the same name may be created after removal; + */ + if (rv == APR_SUCCESS) + { + rv = apr_shm_create(&shm2, SHARED_SIZE, SHARED_FILENAME, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + if (rv != APR_SUCCESS) { + return; + } + ABTS_PTR_NOTNULL(tc, shm2); + + rv = apr_shm_destroy(shm2); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); + } + + rv = apr_shm_destroy(shm); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); + + /* Now ensure no named resource remains which we may attach to */ + rv = apr_shm_attach(&shm, SHARED_FILENAME, p); + ABTS_TRUE(tc, rv != 0); +} + +#endif + +abts_suite *testshm(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + +#if APR_HAS_SHARED_MEMORY + abts_run_test(suite, test_anon_create, NULL); + abts_run_test(suite, test_check_size, NULL); + abts_run_test(suite, test_shm_allocate, NULL); +#if APR_HAS_FORK + abts_run_test(suite, test_anon, NULL); +#endif + abts_run_test(suite, test_named, NULL); + abts_run_test(suite, test_named_remove, NULL); + abts_run_test(suite, test_named_delete, NULL); +#endif + + return suite; +} + + |