You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Ben Hyde <bh...@gensym.com> on 1997/12/15 22:12:57 UTC

Fixing mod_example.c

This isn't a patch, since I haven't tried it on the NT yet, but I wanted to
throw it over the wall before I go home to my dear family.    - ben h.


mod_example has global state that needed guarding to assure thread safety.

> cvs diff -u -b src/modules/example/mod_example.c
Index: src/modules/example/mod_example.c
===================================================================
RCS file: /cvs/apachen/src/modules/example/mod_example.c,v
retrieving revision 1.22
diff -u -b -r1.22 mod_example.c
--- mod_example.c	1997/10/22 20:30:03	1.22
+++ mod_example.c	1997/12/15 22:24:04
@@ -59,6 +59,7 @@
 #include "httpd.h"
 #include "http_config.h"
 #include "http_core.h"
+#include "multithread.h"
 #include "http_log.h"
 #include "http_main.h"
 #include "http_protocol.h"
@@ -105,6 +106,30 @@
 } excfg;
 
 /*
+ * The best most portable modules are written to be thread safe, i.e. they take
+ * care to assure that any access to global state they maintain is approprately
+ * serialized.  Any failure to be thread safe will only show up in those
+ * configruations of Apache where a single process address space is used to
+ * handle multiple requests simultanously.  Currently, Dec97, this is only true
+ * on Windows, but lots of people would like to see it available more widely.
+ *
+ * We use a mutex for our serialization here.  The mutex are provided by the
+ * Apache Core and are implemented on some platform specific substrate, they may
+ * consume some operating system resources.  Their life cycle is bracketed by
+ * create_mutex, and destroy_mutex.  Here we let process termination destroy our
+ * single module wide mutex.  Mutex are used via the nesting bracketing pair of
+ * routines acquire_mutex, and release_mutex.  Of course, the thread may block
+ * upon calling acquire_mutex.
+ *
+ * We must guard two data structures: memory pool "example_pool", and the log
+ * stored in the table "static_calls_made".  We acquire the mutex only for short
+ * intervals. */
+
+static mutex *example_mutex = NULL;
+
+#define begin_serial() {block_alarms(); (void)acquire_mutex(example_mutex);}
+#define end_serial()   {(void)release_mutex(example_mutex);  unblock_alarms();}
+/*
  * Let's set up a module-local static cell to point to the accreting callback
  * trace.  As each API callback is made to us, we'll tack on the particulars
  * to whatever we've already recorded.  To avoid massive memory bloat as
@@ -279,6 +304,15 @@
  */
 static void setup_module_cells()
 {
+  /* We must serialized access to shared data */
+  if ( NULL == example_mutex ) {
+    /* Thank goodness, no need to do mutual exclustion around the global 
+     * variable example_mutex. */
+    example_mutex = create_mutex(NULL);
+
+    begin_serial();
+    {
+      
     /*
      * If we haven't already allocated our module-private pool, do so now.
      */
@@ -292,6 +326,25 @@
     if (static_calls_made == NULL) {
         static_calls_made = make_table(example_pool, 16);
     };
+    }
+    end_serial();
+  }
+}
+
+static char * get_static_calls_made(char *key)
+{
+  char *result;
+  begin_serial();
+  result = table_get(static_calls_made, key);
+  end_serial();
+  return result;
+}
+
+static set_static_calls_made(char *key, char *value)
+{
+  begin_serial();
+  table_set(static_calls_made, key, value);
+  end_serial();
 }
 
 /*
@@ -348,6 +401,8 @@
          * Make a new sub-pool and copy any existing trace to it.  Point the
          * trace cell at the copied value.
          */
+        begin_serial();
+	{
         p = make_sub_pool(example_pool);
         if (trace != NULL) {
             trace = pstrdup(p, trace);
@@ -360,6 +415,8 @@
             destroy_pool(example_subpool);
         }
         example_subpool = p;
+	}
+        end_serial();
         trace_copy = trace;
     }
     /*
@@ -380,7 +437,7 @@
         char *key;
 
         key = pstrcat(p, note, ":", where, NULL);
-        if (table_get(static_calls_made, key) != NULL) {
+        if (get_static_calls_made( key) != NULL) {
             /*
              * Been here, done this.
              */
@@ -391,7 +448,7 @@
              * First time for this combination of routine and environment -
              * log it so we don't do it again.
              */
-            table_set(static_calls_made, key, "been here");
+            set_static_calls_made(key, "been here");
         }
     }
     addon = pstrcat(p, "   <LI>\n", "    <DL>\n", "     <DT><SAMP>",