"Fossies" - the Fresh Open Source Software Archive

Member "apr-1.7.0/test/testprocmutex.c" (19 Apr 2017, 8950 Bytes) of package /linux/www/apr-1.7.0.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "testprocmutex.c": 1.6.5_vs_1.7.0.

    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 "apr_shm.h"
   18 #include "apr_thread_proc.h"
   19 #include "apr_file_io.h"
   20 #include "apr_proc_mutex.h"
   21 #include "apr_errno.h"
   22 #include "apr_general.h"
   23 #include "apr_strings.h"
   24 #include "apr_getopt.h"
   25 #include <stdio.h>
   26 #include <stdlib.h>
   27 #include "testutil.h"
   28 
   29 #if APR_HAS_FORK
   30 
   31 #define MAX_ITER 200
   32 #define CHILDREN 6
   33 #define MAX_COUNTER (MAX_ITER * CHILDREN)
   34 #define MAX_WAIT_USEC (1000*1000)
   35 
   36 static apr_proc_mutex_t *proc_lock;
   37 static volatile int *x;
   38 
   39 typedef struct lockmech {
   40     apr_lockmech_e num;
   41     const char *name;
   42 } lockmech_t;
   43 
   44 /* a slower more racy way to implement (*x)++ */
   45 static int increment(int n)
   46 {
   47     apr_sleep(1);
   48     return n+1;
   49 }
   50 
   51 static void make_child(abts_case *tc, int trylock, apr_proc_t **proc, apr_pool_t *p)
   52 {
   53     apr_status_t rv;
   54 
   55     *proc = apr_pcalloc(p, sizeof(**proc));
   56 
   57     /* slight delay to allow things to settle */
   58     apr_sleep (1);
   59 
   60     rv = apr_proc_fork(*proc, p);
   61     if (rv == APR_INCHILD) {
   62         int i = 0;
   63         /* The parent process has setup all processes to call apr_terminate
   64          * at exit.  But, that means that all processes must also call
   65          * apr_initialize at startup.  You cannot have an unequal number
   66          * of apr_terminate and apr_initialize calls.  If you do, bad things
   67          * will happen.  In this case, the bad thing is that if the mutex
   68          * is a semaphore, it will be destroyed before all of the processes
   69          * die.  That means that the test will most likely fail.
   70          */
   71         apr_initialize();
   72 
   73         if (apr_proc_mutex_child_init(&proc_lock, NULL, p))
   74             exit(1);
   75 
   76         do {
   77             if (trylock > 0) {
   78                 int wait_usec = 0;
   79 
   80                 while ((rv = apr_proc_mutex_trylock(proc_lock))) {
   81                     if (!APR_STATUS_IS_EBUSY(rv))
   82                         exit(1);
   83                     if (++wait_usec >= MAX_WAIT_USEC)
   84                         exit(1);
   85                     apr_sleep(1);
   86                 }
   87             }
   88             else if (trylock < 0) {
   89                 int wait_usec = 0;
   90 
   91                 while ((rv = apr_proc_mutex_timedlock(proc_lock, 1))) {
   92                     if (!APR_STATUS_IS_TIMEUP(rv))
   93                         exit(1);
   94                     if (++wait_usec >= MAX_WAIT_USEC)
   95                         exit(1);
   96                 }
   97             }
   98             else {
   99                 if (apr_proc_mutex_lock(proc_lock))
  100                     exit(1);
  101             }
  102 
  103             i++;
  104             *x = increment(*x);
  105             if (apr_proc_mutex_unlock(proc_lock))
  106                 exit(1);
  107         } while (i < MAX_ITER);
  108         exit(0);
  109     } 
  110 
  111     ABTS_ASSERT(tc, "fork failed", rv == APR_INPARENT);
  112 }
  113 
  114 /* Wait for a child process and check it terminated with success. */
  115 static void await_child(abts_case *tc, apr_proc_t *proc)
  116 {
  117     int code;
  118     apr_exit_why_e why;
  119     apr_status_t rv;
  120 
  121     rv = apr_proc_wait(proc, &code, &why, APR_WAIT);
  122     ABTS_ASSERT(tc, "child did not terminate with success",
  123              rv == APR_CHILD_DONE && why == APR_PROC_EXIT && code == 0);
  124 }
  125 
  126 static void test_exclusive(abts_case *tc, const char *lockname, 
  127                            lockmech_t *mech)
  128 {
  129     apr_proc_t *child[CHILDREN];
  130     apr_status_t rv;
  131     int n;
  132  
  133     rv = apr_proc_mutex_create(&proc_lock, lockname, mech->num, p);
  134     if (rv == APR_ENOTIMPL) {
  135         /* MacOS lacks TIMED implementation, so don't fail for ENOTIMPL */
  136         fprintf(stderr, "method %s not implemented, ", mech->name);
  137         return;
  138     }
  139     APR_ASSERT_SUCCESS(tc, "create the mutex", rv);
  140  
  141     for (n = 0; n < CHILDREN; n++)
  142         make_child(tc, 0, &child[n], p);
  143 
  144     for (n = 0; n < CHILDREN; n++)
  145         await_child(tc, child[n]);
  146     
  147     ABTS_ASSERT(tc, "Locks don't appear to work", *x == MAX_COUNTER);
  148 
  149     rv = apr_proc_mutex_trylock(proc_lock);
  150     if (rv == APR_ENOTIMPL) {
  151         fprintf(stderr, "%s_trylock() not implemented, ", mech->name);
  152         ABTS_ASSERT(tc, "Default timed trylock not implemented",
  153                     mech->num != APR_LOCK_DEFAULT &&
  154                     mech->num != APR_LOCK_DEFAULT_TIMED);
  155     }
  156     else {
  157         APR_ASSERT_SUCCESS(tc, "check for trylock", rv);
  158 
  159         for (n = 0; n < 2; n++) {
  160             rv = apr_proc_mutex_trylock(proc_lock);
  161             /* Some mech (eg. flock or fcntl) may succeed when the
  162              * lock is re-acquired in the same process.
  163              */
  164             if (rv != APR_SUCCESS) {
  165                 ABTS_ASSERT(tc,
  166                             apr_psprintf(p, "%s_trylock() should be busy => %pm",
  167                                          mech->name, &rv),
  168                             APR_STATUS_IS_EBUSY(rv));
  169             }
  170         }
  171 
  172         rv = apr_proc_mutex_unlock(proc_lock);
  173         APR_ASSERT_SUCCESS(tc, "unlock after trylock check", rv);
  174 
  175         *x = 0;
  176 
  177         for (n = 0; n < CHILDREN; n++)
  178             make_child(tc, 1, &child[n], p);
  179 
  180         for (n = 0; n < CHILDREN; n++)
  181             await_child(tc, child[n]);
  182         
  183         ABTS_ASSERT(tc, "Locks don't appear to work with trylock",
  184                     *x == MAX_COUNTER);
  185     }
  186 
  187 #if APR_HAS_TIMEDLOCKS
  188     rv = apr_proc_mutex_timedlock(proc_lock, 1);
  189     if (rv == APR_ENOTIMPL) {
  190         fprintf(stderr, "%s_timedlock() not implemented, ", mech->name);
  191         ABTS_ASSERT(tc, "Default timed timedlock not implemented",
  192                     mech->num != APR_LOCK_DEFAULT_TIMED);
  193     }
  194     else {
  195         APR_ASSERT_SUCCESS(tc, "check for timedlock", rv);
  196 
  197         for (n = 0; n < 2; n++) {
  198             rv = apr_proc_mutex_timedlock(proc_lock, 1);
  199             /* Some mech (eg. flock or fcntl) may succeed when the
  200              * lock is re-acquired in the same process.
  201              */
  202             if (rv != APR_SUCCESS) {
  203                 ABTS_ASSERT(tc,
  204                             apr_psprintf(p, "%s_timedlock() should time out => %pm",
  205                                          mech->name, &rv),
  206                             APR_STATUS_IS_TIMEUP(rv));
  207             }
  208         }
  209 
  210         rv = apr_proc_mutex_unlock(proc_lock);
  211         APR_ASSERT_SUCCESS(tc, "unlock after timedlock check", rv);
  212 
  213         *x = 0;
  214 
  215         for (n = 0; n < CHILDREN; n++)
  216             make_child(tc, -1, &child[n], p);
  217 
  218         for (n = 0; n < CHILDREN; n++)
  219             await_child(tc, child[n]);
  220         
  221         ABTS_ASSERT(tc, "Locks don't appear to work with timedlock",
  222                     *x == MAX_COUNTER);
  223     }
  224 #endif  /* APR_HAS_TIMEDLOCKS */
  225 }
  226 
  227 static void proc_mutex(abts_case *tc, void *data)
  228 {
  229     apr_status_t rv;
  230     const char *shmname = "tpm.shm";
  231     apr_shm_t *shm;
  232 
  233     /* Use anonymous shm if available. */
  234     rv = apr_shm_create(&shm, sizeof(int), NULL, p);
  235     if (rv == APR_ENOTIMPL) {
  236         apr_file_remove(shmname, p);
  237         rv = apr_shm_create(&shm, sizeof(int), shmname, p);
  238     }
  239 
  240     APR_ASSERT_SUCCESS(tc, "create shm segment", rv);
  241     if (rv != APR_SUCCESS)
  242         return;
  243 
  244     x = apr_shm_baseaddr_get(shm);
  245     test_exclusive(tc, NULL, data);
  246     rv = apr_shm_destroy(shm);
  247     APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv);
  248 }
  249 
  250 
  251 abts_suite *testprocmutex(abts_suite *suite)
  252 {
  253     lockmech_t lockmechs[] = {
  254         {APR_LOCK_DEFAULT, "default"}
  255 #if APR_HAS_FLOCK_SERIALIZE
  256         ,{APR_LOCK_FLOCK, "flock"}
  257 #endif
  258 #if APR_HAS_SYSVSEM_SERIALIZE
  259         ,{APR_LOCK_SYSVSEM, "sysvsem"}
  260 #endif
  261 #if APR_HAS_POSIXSEM_SERIALIZE
  262         ,{APR_LOCK_POSIXSEM, "posix"}
  263 #endif
  264 #if APR_HAS_FCNTL_SERIALIZE
  265         ,{APR_LOCK_FCNTL, "fcntl"}
  266 #endif
  267 #if APR_HAS_PROC_PTHREAD_SERIALIZE
  268         ,{APR_LOCK_PROC_PTHREAD, "proc_pthread"}
  269 #endif
  270         ,{APR_LOCK_DEFAULT_TIMED, "default_timed"}
  271     };
  272     int i;
  273 
  274     suite = ADD_SUITE(suite)
  275     for (i = 0; i < sizeof(lockmechs) / sizeof(lockmechs[0]); i++) {
  276         abts_run_test(suite, proc_mutex, &lockmechs[i]);
  277     }
  278     return suite;
  279 }
  280 
  281 #else /* APR_HAS_FORK */
  282 
  283 static void proc_mutex(abts_case *tc, void *data)
  284 {
  285     ABTS_NOT_IMPL(tc, "APR lacks fork() support");
  286 }
  287 
  288 abts_suite *testprocmutex(abts_suite *suite)
  289 {
  290     suite = ADD_SUITE(suite);
  291     abts_run_test(suite, proc_mutex, NULL);
  292     return suite;
  293 }
  294 #endif /* APR_HAS_FORK */