Hey Nicolas,
good news about mod_neko for apache2.
> If I understand :
> * getenv crash
> * only if putenv was done ??
yes, but it's not "our" getenv. i've added traces to sys.c as you
suggested, but it seems to never get there. It must be some other getenv
call in apache, it occurs well after initialization of mod_neko.
After reading through putenv's manpage, i've tried the following:
putenv(strdup("MOD_NEKO=1"));
and- tadaa: it doesnt crash on me no more.
quoting NOTES from man putenv:
> The putenv() function is not required to be reentrant, and
the one in libc4, libc5 and glibc2.0 is not,
> but the glibc2.1 version is.
>
> Description for libc4, libc5, glibc: If the argument string
is of the form name, and does not contain
> an `=' character, then the variable name is removed from the
environment. If putenv() has to allocate
> a new array environ, and the previous array was also
allocated by putenv(), then it will be freed. In
> no case will the old storage associated to the environment
variable itself be freed.
>
> The libc4 and libc5 and glibc 2.1.2 versions conform to
SUSv2: the pointer string given to putenv() is
> used. In particular, this string becomes part of the
environment; changing it later will change the
> environment. (Thus, it is an error is to call putenv()
with an automatic variable as the argument,
> then return from the calling function while string is still
part of the environment.) However, glibc
> 2.0-2.1.1 differs: a copy of the string is used. On the one
hand this causes a memory leak, and on the
> other hand it violates SUSv2. This has been fixed in
glibc2.1.2.
>
> The 4.4BSD version, like glibc 2.0, uses a copy.
>
> SUSv2 removes the `const' from the prototype, and so does
glibc 2.1.3.
so- things are a bit weird on the putenv front. strdup might obviously
introduce a slight memleak, but to be honest- i dont care.
> I'm not sure which method is best to store Thread-Local variables on
> Linux/OSX. Maybe Pthreads but if it requires additional
dependencies,
> maybe native threads are better ?
the p in pthreads is for POSIX, it doesnt introduce another dependency.
mod_php seems to be using it too; apache only has support for
thread-local mutexes, not thread-local storage--. I've modified
context.h/.c to use pthread_setspecific and friends. It requires the
-pthread flag to be set on gcc. It doesnt crash, but i dont know how to
properly test this currently. I'll probably run some threading tests
later on to see how this works out.
> > what do you suggest to do about the build procedure here? i
currently
> > use apxs2 (the "apache extension tool") to compile, the least we
must do
> > is to append the output of apr-config --libs --cflags to our gcc
line..
>
> Uhm.
> You can't simply have the user specify an include path ? That would
fit
> better the current system for compiling neko libraries.
true- although in case of apache2, at least on my gentoo, we need *two*
additional -I flags, as httpd.h (found in /usr/include/apache2) needs
headers from /usr/include/apr-0. Seems we'd need to adapt install.neko
to support this..
i've re-integrated the 2.0 stuff into the 1.x mod_neko.c with #ifdefs as
discussed. Seems to work fine here, although i have no way (or interest
:) to test with 1.x.
Find the patch attached, here's how i currently build mod_neko for ap2:
/usr/sbin/apxs2 -c -I $(apr-config --includedir) -I
/usr/local/include/neko -I ../../vm/ -lneko mod_neko.c cgi.c
gcc -fPIC -shared -o mod_neko.ndll -lneko -I/usr/local/include/neko
-I../../vm/ -I/usr/include/apache2/ -I/usr/include/apr-0/ -lapr-0 cgi.c
mod_neko.c
additionally, i had to move setting of r->content_type to the end of
neko_handler_rec. hope this doesnt bug anything.
regards,
-dan
--
http://0xDF.com/
http://iterative.org/
Index: Makefile
===================================================================
RCS file: /cvsroot/neko/Makefile,v
retrieving revision 1.37
diff -u -r1.37 Makefile
--- Makefile 10 May 2006 08:22:09 -0000 1.37
+++ Makefile 1 Jun 2006 13:46:26 -0000
@@ -1,6 +1,6 @@
### CONFIG
-CFLAGS = -Wall -O3 -fPIC -fomit-frame-pointer -I vm -DCOMPACT_TABLE
+CFLAGS = -Wall -O3 -fPIC -fomit-frame-pointer -I vm -DCOMPACT_TABLE -pthread
MAKESO = gcc -shared -WBsymbolic
LIBNEKO_NAME = libneko.so
LIBNEKO_LIBS = -ldl -lgc -lm
Index: libs/mod_neko/cgi.c
===================================================================
RCS file: /cvsroot/neko/libs/mod_neko/cgi.c,v
retrieving revision 1.14
diff -u -r1.14 cgi.c
--- libs/mod_neko/cgi.c 27 Apr 2006 15:22:51 -0000 1.14
+++ libs/mod_neko/cgi.c 1 Jun 2006 13:47:50 -0000
@@ -17,6 +17,17 @@
#include <neko.h>
#include "mod_neko.h"
+#ifdef APACHE_IS_20
+#define TABLE_GET apr_table_get
+#define TABLE_SET apr_table_set
+#define TABLE_ADD apr_table_add
+#else
+#define TABLE_GET ap_table_get
+#define TABLE_SET ap_table_set
+#define TABLE_ADD ap_table_add
+#define HTTP_TEMPORARY_REDIRECT REDIRECT
+#endif
+
#define PARSE_HEADER(start,cursor) \
cursor = start; \
if( *cursor == '"' ) { \
@@ -51,7 +62,7 @@
<doc>Return a cookie list as a (name,value) chained list</doc>
**/
static value get_cookies() {
- const char *k = ap_table_get(CONTEXT()->r->headers_in,"Cookie");
+ const char *k = TABLE_GET(CONTEXT()->r->headers_in,"Cookie");
char *start, *end;
value p = val_null, tmp;
if( k == NULL )
@@ -90,7 +101,7 @@
val_buffer(b,v);
buffer_append(b,";");
str = buffer_to_string(b);
- ap_table_add(c->r->headers_out,"Set-Cookie",val_string(str));
+ TABLE_ADD(c->r->headers_out,"Set-Cookie",val_string(str));
return val_true;
}
@@ -131,8 +142,8 @@
mcontext *c = CONTEXT();
val_check(s,string);
HEADERS_NOT_SENT("Redirection");
- ap_table_set(c->r->headers_out,"Location",val_string(s));
- c->r->status = REDIRECT;
+ TABLE_SET(c->r->headers_out,"Location",val_string(s));
+ c->r->status = HTTP_TEMPORARY_REDIRECT;
return val_true;
}
@@ -161,7 +172,7 @@
c->content_type = alloc_string(val_string(k));
c->r->content_type = val_string(c->content_type);
} else
- ap_table_set(c->r->headers_out,val_string(s),val_string(k));
+ TABLE_SET(c->r->headers_out,val_string(s),val_string(k));
return val_true;
}
@@ -172,7 +183,7 @@
static value get_client_header( value s ) {
mcontext *c = CONTEXT();
val_check(s,string);
- return alloc_string( ap_table_get(c->r->headers_in,val_string(s)) );
+ return alloc_string( TABLE_GET(c->r->headers_in,val_string(s)) );
}
/**
@@ -351,7 +362,7 @@
// PARSE "POST" PARAMS
if( c->post_data != NULL ) {
- const char *ctype = ap_table_get(c->r->headers_in,"Content-Type");
+ const char *ctype = TABLE_GET(c->r->headers_in,"Content-Type");
if( ctype && strstr(ctype,"application/octet-stream") != NULL )
return p;
if( ctype && strstr(ctype,"multipart/form-data") != NULL )
Index: libs/mod_neko/mod_neko.c
===================================================================
RCS file: /cvsroot/neko/libs/mod_neko/mod_neko.c,v
retrieving revision 1.17
diff -u -r1.17 mod_neko.c
--- libs/mod_neko/mod_neko.c 28 Mar 2006 12:06:43 -0000 1.17
+++ libs/mod_neko/mod_neko.c 1 Jun 2006 13:47:52 -0000
@@ -16,6 +16,12 @@
/* ************************************************************************ */
#include "mod_neko.h"
+#ifdef APACHE_IS_20
+#define FINFO_MTIME finfo.mtime
+#else
+#define FINFO_MTIME finfo.st_mtime
+#endif
+
typedef struct cache {
value file;
value main;
@@ -41,7 +47,9 @@
static void send_headers( mcontext *c ) {
if( !c->headers_sent ) {
- ap_send_http_header(c->r);
+# ifndef APACHE_IS_20
+ ap_send_http_header(c->r);
+# endif
c->headers_sent = true;
}
}
@@ -60,7 +68,7 @@
value fname = alloc_string(r->filename);
while( c != NULL ) {
if( val_compare(fname,c->file) == 0 ) {
- if( r->finfo.st_mtime == c->time )
+ if( r->FINFO_MTIME == c->time )
return c->main;
if( prev == NULL )
context_set(cache_root,c->next);
@@ -87,7 +95,7 @@
while( c != NULL ) {
if( val_compare(fname,c->file) == 0 ) {
c->main = main;
- c->time = r->finfo.st_mtime;
+ c->time = r->FINFO_MTIME;
return;
}
c = c->next;
@@ -95,7 +103,7 @@
c = (cache*)alloc_root(sizeof(struct cache) / sizeof(value));
c->file = fname;
c->main = main;
- c->time = r->finfo.st_mtime;
+ c->time = r->FINFO_MTIME;
c->next = (cache*)context_get(cache_root);
context_set(cache_root,c);
}
@@ -112,7 +120,6 @@
ctx.allow_write = true;
ctx.headers_sent = false;
ctx.content_type = alloc_string("text/html");
- r->content_type = val_string(ctx.content_type);
if( ap_setup_client_block(r,REQUEST_CHUNKED_ERROR) != 0 ) {
send_headers(&ctx);
@@ -187,16 +194,50 @@
return OK;
}
+ r->content_type = val_string(ctx.content_type);
+
send_headers(&ctx);
- return OK;
+ return OK;
}
static int neko_handler( request_rec *r ) {
+# ifdef APACHE_IS_20
+ if(strcmp(r->handler,"neko-handler"))
+ return DECLINED;
+# endif
+
int ret = neko_handler_rec(r);
neko_gc_major();
return ret;
}
+
+#ifdef APACHE_IS_20
+
+static int neko_init( apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s ) {
+ cache_root = context_new();
+ putenv(strdup("MOD_NEKO=1"));
+ neko_global_init(&s);
+ return OK;
+}
+
+static void neko_register_hooks( apr_pool_t *p ) {
+ ap_hook_post_config( neko_init, NULL, NULL, APR_HOOK_MIDDLE );
+ ap_hook_handler( neko_handler, NULL, NULL, APR_HOOK_LAST );
+};
+
+module AP_MODULE_DECLARE_DATA neko_module = {
+ STANDARD20_MODULE_STUFF,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /*neko_module_cmds, */
+ neko_register_hooks
+};
+
+#else /* !APACHE_IS_20 */
+
static void neko_init(server_rec *s, pool *p) {
cache_root = context_new();
putenv("MOD_NEKO=1");
@@ -204,30 +245,32 @@
}
static const handler_rec neko_handlers[] = {
- {"neko-handler", neko_handler},
- {NULL}
+ {"neko-handler", neko_handler},
+ {NULL}
};
module MODULE_VAR_EXPORT neko_module = {
- STANDARD_MODULE_STUFF,
- neko_init,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- neko_handlers,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
+ STANDARD_MODULE_STUFF,
+ neko_init,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ neko_handlers,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
};
+#endif /* APACHE_IS_20 */
+
/* ************************************************************************ */
Index: libs/mod_neko/mod_neko.h
===================================================================
RCS file: /cvsroot/neko/libs/mod_neko/mod_neko.h,v
retrieving revision 1.9
diff -u -r1.9 mod_neko.h
--- libs/mod_neko/mod_neko.h 4 Mar 2006 13:46:39 -0000 1.9
+++ libs/mod_neko/mod_neko.h 1 Jun 2006 13:47:52 -0000
@@ -39,6 +39,10 @@
#define CONTEXT() ((mcontext*)neko_vm_custom(neko_vm_current()))
+#ifdef STANDARD20_MODULE_STUFF
+#define APACHE_IS_20
+#endif
+
#endif
/* ************************************************************************ */
Index: src/tools/install.neko
===================================================================
RCS file: /cvsroot/neko/src/tools/install.neko,v
retrieving revision 1.27
diff -u -r1.27 install.neko
--- src/tools/install.neko 4 Mar 2006 12:48:15 -0000 1.27
+++ src/tools/install.neko 1 Jun 2006 13:47:54 -0000
@@ -78,6 +78,7 @@
"/usr/local/lib",
"/usr/local/lib/mysql",
"/usr/include/httpd",
+ "/usr/include/apache2",
);
exec = function(cmd) {
Index: vm/context.c
===================================================================
RCS file: /cvsroot/neko/vm/context.c,v
retrieving revision 1.6
diff -u -r1.6 context.c
--- vm/context.c 27 Apr 2006 14:36:24 -0000 1.6
+++ vm/context.c 1 Jun 2006 13:47:54 -0000
@@ -46,29 +46,31 @@
/* ************************************************************************ */
#include "objtable.h"
#include <stdlib.h>
+#include <pthread.h>
struct _context {
- void *data;
+ pthread_key_t key;
};
_context *context_new() {
- _context *c = malloc(sizeof(_context));
- c->data = NULL;
- return c;
+ _context *ctx = malloc(sizeof(_context));
+ pthread_key_create( &ctx->key, NULL );
+ return ctx;
}
void context_delete( _context *ctx ) {
+ pthread_key_delete( ctx->key );
free(ctx);
}
void context_set( _context *ctx, void *data ) {
- ctx->data = data;
+ pthread_setspecific( ctx->key, data );
}
void *context_get( _context *ctx ) {
if( ctx == NULL )
return NULL;
- return ctx->data;
+ return pthread_getspecific( ctx->key );
}
#endif
--
Neko : One VM to run them all
(http://nekovm.org)