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>",