From: David Hedbor Date: Thu, 2 Nov 2000 18:53:47 +0000 (+0000) Subject: Initial caudium support. X-Git-Tag: php-4.0.4RC3~376 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8aa6f6d55c01f411a1dbafe14cd8faf43b2430ec;p=php Initial caudium support. --- diff --git a/sapi/caudium/Makefile.in b/sapi/caudium/Makefile.in new file mode 100644 index 0000000000..6063dd209b --- /dev/null +++ b/sapi/caudium/Makefile.in @@ -0,0 +1,5 @@ + +LTLIBRARY_NAME = libsapi.la +LTLIBRARY_SOURCES = caudium.c + +include $(top_srcdir)/build/ltlib.mk diff --git a/sapi/caudium/README b/sapi/caudium/README new file mode 100644 index 0000000000..ae1289a1ac --- /dev/null +++ b/sapi/caudium/README @@ -0,0 +1,15 @@ +Embedded Caudium PHP support. It seems to work but isn't tested +much. Due to a design choice it requires _Pike_ threads and a +thread-safe PHP. It doesn't however require _Caudium_ to run in +threaded mode. Due to the design, utilization of multiple processors +should be pretty good. + +It requires a new Pike 7.0 and Caudium. It will not work with +Roxen. Also, with the help of the VIRTUAL_DIR code in PHP, PHP +execution should be very similar to that of mod_php or the cgi +script. + +If you have any questions, please contact me, David Hedbor +(neotron@php.net or neotron@caudium.net). + + diff --git a/sapi/caudium/TODO b/sapi/caudium/TODO new file mode 100644 index 0000000000..c4352f93fc --- /dev/null +++ b/sapi/caudium/TODO @@ -0,0 +1,30 @@ +TODO: + +- Rewriting header handling so that more than one header with the same + name can be set (most importantly, cookies). +- per-virtual-server configuration +- configurable limit of number of concurrent PHP executions +- fix setting of auth info. + +FIXED: ++ => fixed +- => not fixed and no fix planned +? => Maybe fixed, maybe not. + ++ fix backtraces + Uses th_farm, thus problem is fixed ++ exit in PHP exits Caudium + Name conflict with do_exit in Pike and PHP. Reported to both teams. ++ POST newline added? + Was a Caudium bug. ++ use th_farm + Yeppers. Works great. +- change cwd in single threaded mode + There will be no single threaded mode support. The Caudium module + will requite PHP ZTS and Pike threads to run. Single threaded PHP + is rather uninteresting anyway. +? Recursive mutex lock problem: + Dunno if this is fixed. Major rewrite so it would have to be + retested. + + diff --git a/sapi/caudium/caudium.c b/sapi/caudium/caudium.c new file mode 100644 index 0000000000..083d04685f --- /dev/null +++ b/sapi/caudium/caudium.c @@ -0,0 +1,793 @@ +/* + +----------------------------------------------------------------------+ + | PHP version 4.0 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.02 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.php.net/license/2_02.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: David Hedbor | + | Based on aolserver SAPI by Sascha Schumann | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#include "php.h" +#ifdef HAVE_CAUDIUM + +#include "php_ini.h" +#include "php_globals.h" +#include "SAPI.h" +#include "php_main.h" +#include "ext/standard/info.h" + +#include "php_version.h" + +/* Pike Include Files + * + * conflicts with pike avoided by only using long names. Requires a new + * Pike 0.7 since it was implemented for this interface only. + * + */ +#define NO_PIKE_SHORTHAND + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef ZTS +/* Need thread safety */ +#error You need to compile PHP with threads. +#endif + +#ifndef PIKE_THREADS +#error The PHP4 module requires that your Pike has thread support. +#endif + +#undef HIDE_GLOBAL_VARIABLES +#undef REVEAL_GLOBAL_VARIABLES +#define HIDE_GLOBAL_VARIABLES() +#define REVEAL_GLOBAL_VARIABLES() + +/* php_caudium_request is per-request object storage */ + +typedef struct +{ + struct mapping *request_data; + struct object *my_fd_obj; + struct svalue done_cb; + struct pike_string *filename; + int my_fd; + SLS_D; +} php_caudium_request; + + +void pike_module_init(void); +void pike_module_exit(void); +static void free_struct(SLS_D); +void f_php_caudium_request_handler(INT32 args); + +/* Defines to get to the data supplied when the script is started. */ + +/* Per thread storage area id... */ +static int caudium_globals_id; + +#define GET_THIS() php_caudium_request *_request = ts_resource(caudium_globals_id) +#define THIS _request +#define PTHIS ((php_caudium_request *)(Pike_fp->current_storage)) +/* File descriptor integer. Used to write directly to the FD without + * passing Pike + */ +#define MY_FD (THIS->my_fd) + +/* FD object. Really a PHPScript object from Pike which implements a couple + * of functions to handle headers, writing and buffering. + */ +#define MY_FD_OBJ ((struct object *)(THIS->my_fd_obj)) + +/* Mapping with data supplied from the calling Caudium module. Contains + * a mapping with headers, an FD object etc. + */ +#define REQUEST_DATA ((struct mapping *)(THIS->request_data)) + + +#if 0 && defined(_REENTRANT) && !defined(CAUDIUM_USE_ZTS) +/* Lock used to serialize the PHP execution. If CAUDIUM_USE_ZTS is defined, we + * are using the PHP thread safe mechanism instead. + */ +static PIKE_MUTEX_T caudium_php_execution_lock; +# define PHP_INIT_LOCK() mt_init(&caudium_php_execution_lock) +# define PHP_LOCK(X) THREADS_ALLOW();mt_lock(&caudium_php_execution_lock);THREADS_DISALLOW() +# define PHP_UNLOCK(X) mt_unlock(&caudium_php_execution_lock); +# define PHP_DESTROY() mt_destroy(&caudium_php_execution_lock) +#else /* !_REENTRANT */ +# define PHP_INIT_LOCK() +# define PHP_LOCK(X) +# define PHP_UNLOCK(X) +# define PHP_DESTROY() +#endif /* _REENTRANT */ + +extern int fd_from_object(struct object *o); +static unsigned char caudium_php_initialized; + +/* This allows calling of pike functions from the PHP callbacks, + * which requires the Pike interpreter to be locked. + */ +#define THREAD_SAFE_RUN(COMMAND, what) do {\ + struct thread_state *state;\ + if((state = thread_state_for_id(th_self()))!=NULL) {\ + if(!state->swapped) {\ + COMMAND;\ + } else {\ + mt_lock(&interpreter_lock);\ + SWAP_IN_THREAD(state);\ + COMMAND;\ + SWAP_OUT_THREAD(state);\ + mt_unlock(&interpreter_lock);\ + }\ + }\ +} while(0) + +struct program *php_program; + + +/* To avoid executing a PHP script from a PHP callback, which would + * create a deadlock, a global thread id is used. If the thread calling the + * php-script is the same as the current thread, it fails. + */ +//static int current_thread = -1; + + +/* Low level header lookup. Basically looks for the named header in the mapping + * headers in the supplied options mapping. + */ + +INLINE static struct svalue *lookup_header(char *headername) +{ + struct svalue *headers, *value; + struct pike_string *sind; + GET_THIS(); + sind = make_shared_string("env"); + headers = low_mapping_string_lookup(REQUEST_DATA, sind); + free_string(sind); + if(!headers || headers->type != PIKE_T_MAPPING) return NULL; + sind = make_shared_string(headername); + value = low_mapping_string_lookup(headers->u.mapping, sind); + free_string(sind); + if(!value) return NULL; + return value; +} + +/* Lookup a header in the mapping and return the value as a string, or + * return the default if it's missing + */ +INLINE static char *lookup_string_header(char *headername, char *default_value) +{ + struct svalue *head = NULL; + THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup"); + if(!head || head->type != PIKE_T_STRING) + return default_value; + return head->u.string->str; +} + +/* Lookup a header in the mapping and return the value as if it's an integer + * and otherwise return the default. + */ +INLINE static int lookup_integer_header(char *headername, int default_value) +{ + struct svalue *head = NULL; + THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup"); + if(!head || head->type != PIKE_T_INT) + return default_value; + return head->u.integer; +} + +/* + * php_caudium_low_ub_write() writes data to the client connection. Might be + * rewritten to do more direct IO to save CPU and the need to lock the + * interpreter for better threading. + */ + +static int php_caudium_low_ub_write(const char *str, uint str_length) { + int sent_bytes = 0; + struct pike_string *to_write = NULL; + PLS_FETCH(); + GET_THIS(); + if(!MY_FD_OBJ->prog) { + PG(connection_status) = PHP_CONNECTION_ABORTED; + zend_bailout(); + return -1; + } + to_write = make_shared_binary_string(str, str_length); + push_string(to_write); + safe_apply(MY_FD_OBJ, "write", 1); + if(Pike_sp[-1].type == PIKE_T_INT) + sent_bytes = Pike_sp[-1].u.integer; + pop_stack(); + if(sent_bytes != str_length) { + /* This means the connection is closed. Dead. Gone. *sniff* */ + PG(connection_status) = PHP_CONNECTION_ABORTED; + zend_bailout(); + } + return sent_bytes; +} + +/* + * php_caudium_sapi_ub_write() calls php_caudium_low_ub_write in a Pike thread + * safe manner. + */ + +static int +php_caudium_sapi_ub_write(const char *str, uint str_length) +{ + PLS_FETCH(); + GET_THIS(); + int sent_bytes = 0, fd = MY_FD; + if(fd) + { + for(sent_bytes=0;sent_bytes < str_length;) + { + int written; + written = fd_write(fd, str + sent_bytes, str_length - sent_bytes); + if(written < 0) + { + switch(errno) + { + default: + /* This means the connection is closed. Dead. Gone. *sniff* */ + PG(connection_status) = PHP_CONNECTION_ABORTED; + zend_bailout(); + return sent_bytes; + case EINTR: + case EWOULDBLOCK: + continue; + } + + } else { + sent_bytes += written; + } + } + } else { + THREAD_SAFE_RUN(sent_bytes = php_caudium_low_ub_write(str, str_length), + "write"); + } + return sent_bytes; +} + +/* php_caudium_set_header() sets a header in the header mapping. Called in a + * thread safe manner from php_caudium_sapi_header_handler. + */ +static void php_caudium_set_header(char *header_name, char *value, char *p) +{ + struct svalue hsval; + struct pike_string *hval, *ind, *hind; + struct mapping *headermap; + struct svalue *s_headermap; + GET_THIS(); + hval = make_shared_string(value); + ind = make_shared_string(" _headers"); + hind = make_shared_binary_string(header_name, + (int)(p - header_name)); + + s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind); + if(!s_headermap) + { + struct svalue mappie; + mappie.type = PIKE_T_MAPPING; + headermap = allocate_mapping(1); + mappie.u.mapping = headermap; + mapping_string_insert(REQUEST_DATA, ind, &mappie); + free_mapping(headermap); + } else + headermap = s_headermap->u.mapping; + + hsval.type = PIKE_T_STRING; + hsval.u.string = hval; + mapping_string_insert(headermap, hind, &hsval); + + free_string(hval); + free_string(ind); + free_string(hind); +} + +/* + * php_caudium_sapi_header_handler() sets a HTTP reply header to be + * sent to the client. + */ +static int +php_caudium_sapi_header_handler(sapi_header_struct *sapi_header, + sapi_headers_struct *sapi_headers SLS_DC) +{ + char *header_name, *header_content, *p; + header_name = sapi_header->header; + header_content = p = strchr(header_name, ':'); + + if(p) { + do { + header_content++; + } while(*header_content == ' '); + THREAD_SAFE_RUN(php_caudium_set_header(header_name, header_content, p), "header handler"); + } + sapi_free_header(sapi_header); + return 0; +} + +/* + * php_caudium_sapi_send_headers() flushes the headers to the client. + * Called before real content is sent by PHP. + */ + +static int +php_caudium_low_send_headers(sapi_headers_struct *sapi_headers SLS_DC) +{ + PLS_FETCH(); + struct pike_string *ind; + struct svalue *s_headermap; + GET_THIS(); + if(!MY_FD_OBJ->prog) { + PG(connection_status) = PHP_CONNECTION_ABORTED; + zend_bailout(); + return SAPI_HEADER_SEND_FAILED; + } + ind = make_shared_string(" _headers"); + s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind); + free_string(ind); + + push_int(SG(sapi_headers).http_response_code); + if(s_headermap && s_headermap->type == PIKE_T_MAPPING) + ref_push_mapping(s_headermap->u.mapping); + else + push_int(0); + safe_apply(MY_FD_OBJ, "send_headers", 2); + pop_stack(); + + return SAPI_HEADER_SENT_SUCCESSFULLY; +} + +static int +php_caudium_sapi_send_headers(sapi_headers_struct *sapi_headers SLS_DC) +{ + int res = 0; + THREAD_SAFE_RUN(res = php_caudium_low_send_headers(sapi_headers SLS_CC), "send headers"); + return res; +} + +/* + * php_caudium_sapi_read_post() reads a specified number of bytes from + * the client. Used for POST/PUT requests. + */ + +INLINE static int php_caudium_low_read_post(char *buf, uint count_bytes) +{ + uint total_read = 0; + GET_THIS(); + PLS_FETCH(); + + if(!MY_FD_OBJ->prog) + { + PG(connection_status) = PHP_CONNECTION_ABORTED; + zend_bailout(); + return -1; + } + push_int(count_bytes); + safe_apply(MY_FD_OBJ, "read_post", 1); + if(Pike_sp[-1].type == PIKE_T_STRING) { + MEMCPY(buf, Pike_sp[-1].u.string->str, + (total_read = Pike_sp[-1].u.string->len)); + buf[total_read] = '\0'; + } else + total_read = 0; + pop_stack(); + return total_read; +} + +static int +php_caudium_sapi_read_post(char *buf, uint count_bytes SLS_DC) +{ + uint total_read = 0; + THREAD_SAFE_RUN(total_read = php_caudium_low_read_post(buf, count_bytes), "read post"); + return total_read; +} + +/* + * php_caudium_sapi_read_cookies() returns the Cookie header from + * the HTTP request header + */ + +static char * +php_caudium_sapi_read_cookies(SLS_D) +{ + char *cookies; + cookies = lookup_string_header("HTTP_COOKIE", NULL); + return cookies; +} + +static void php_info_caudium(ZEND_MODULE_INFO_FUNC_ARGS) +{ + /* char buf[512]; */ + php_info_print_table_start(); + php_info_print_table_row(2, "SAPI module version", "$Id$"); + /* php_info_print_table_row(2, "Build date", Ns_InfoBuildDate()); + php_info_print_table_row(2, "Config file path", Ns_InfoConfigFile()); + php_info_print_table_row(2, "Error Log path", Ns_InfoErrorLog()); + php_info_print_table_row(2, "Installation path", Ns_InfoHomePath()); + php_info_print_table_row(2, "Hostname of server", Ns_InfoHostname()); + php_info_print_table_row(2, "Source code label", Ns_InfoLabel()); + php_info_print_table_row(2, "Server platform", Ns_InfoPlatform()); + snprintf(buf, 511, "%s/%s", Ns_InfoServerName(), Ns_InfoServerVersion()); + php_info_print_table_row(2, "Server version", buf); + snprintf(buf, 511, "%d day(s), %02d:%02d:%02d", + uptime / 86400, + (uptime / 3600) % 24, + (uptime / 60) % 60, + uptime % 60); + php_info_print_table_row(2, "Server uptime", buf); + */ + php_info_print_table_end(); +} + +static zend_module_entry php_caudium_module = { + "Caudium", + NULL, + NULL, + NULL, + NULL, + NULL, + php_info_caudium, + STANDARD_MODULE_PROPERTIES +}; + +static int php_caudium_startup(sapi_module_struct *sapi_module) +{ + if(php_module_startup(sapi_module) == FAILURE + || zend_startup_module(&php_caudium_module) == FAILURE) { + return FAILURE; + } else { + return SUCCESS; + } +} + +/* this structure is static (as in "it does not change") */ + +static sapi_module_struct sapi_module = { + "caudium", + "Caudium", + php_module_startup, /* startup */ + php_module_shutdown_wrapper, /* shutdown */ + NULL, /* activate */ + NULL, /* deactivate */ + php_caudium_sapi_ub_write, /* unbuffered write */ + NULL, /* flush */ + NULL, /* get uid */ + NULL, /* getenv */ + php_error, /* error handler */ + php_caudium_sapi_header_handler, /* header handler */ + php_caudium_sapi_send_headers, /* send headers handler */ + NULL, /* send header handler */ + php_caudium_sapi_read_post, /* read POST data */ + php_caudium_sapi_read_cookies, /* read Cookies */ + NULL, /* register server variables */ + NULL, /* Log message */ + NULL, /* Block interruptions */ + NULL, /* Unblock interruptions */ + + STANDARD_SAPI_MODULE_PROPERTIES +}; + +/* + * php_caudium_hash_environment() populates the php script environment + * with a number of variables. HTTP_* variables are created for + * the HTTP header data, so that a script can access these. + */ +#define ADD_STRING(name) \ + MAKE_STD_ZVAL(pval); \ + pval->type = IS_STRING; \ + pval->value.str.len = strlen(buf); \ + pval->value.str.val = estrndup(buf, pval->value.str.len); \ + zend_hash_update(&EG(symbol_table), name, sizeof(name), \ + &pval, sizeof(zval *), NULL) + +static void +php_caudium_hash_environment(CLS_D ELS_DC PLS_DC SLS_DC) +{ + int i; + char buf[512]; + zval *pval; + struct svalue *headers; + struct pike_string *sind; + struct array *indices; + struct svalue *ind, *val; + GET_THIS(); + sind = make_shared_string("env"); + headers = low_mapping_string_lookup(REQUEST_DATA, sind); + free_string(sind); + if(headers && headers->type == PIKE_T_MAPPING) { + indices = mapping_indices(headers->u.mapping); + for(i = 0; i < indices->size; i++) { + ind = &indices->item[i]; + val = low_mapping_lookup(headers->u.mapping, ind); + if(ind && ind->type == PIKE_T_STRING && + val && val->type == PIKE_T_STRING) { + int buf_len; + buf_len = MIN(511, ind->u.string->len); + strncpy(buf, ind->u.string->str, buf_len); + buf[buf_len] = '\0'; /* Terminate correctly */ + MAKE_STD_ZVAL(pval); + pval->type = IS_STRING; + pval->value.str.len = val->u.string->len; + pval->value.str.val = estrndup(val->u.string->str, pval->value.str.len); + + zend_hash_update(&EG(symbol_table), buf, buf_len + 1, &pval, sizeof(zval *), NULL); + } + } + free_array(indices); + } + + /* + MAKE_STD_ZVAL(pval); + pval->type = IS_LONG; + pval->value.lval = Ns_InfoBootTime(); + zend_hash_update(&EG(symbol_table), "SERVER_BOOTTIME", sizeof("SERVER_BOOTTIME"), &pval, sizeof(zval *), NULL); + */ +} + +/* + * php_caudium_module_main() is called by the per-request handler and + * "executes" the script + */ + +static void php_caudium_module_main(php_caudium_request *ureq) +{ + int res, len; + char *dir; + zend_file_handle file_handle; + struct thread_state *state; + extern struct program *thread_id_prog; + // struct php_caudium_request *ureq; + SLS_FETCH(); + CLS_FETCH(); + PLS_FETCH(); + ELS_FETCH(); + GET_THIS(); + // ureq = (struct php_caudium_request *)ud; + THIS->filename = ureq->filename; + THIS->done_cb = ureq->done_cb; + THIS->my_fd_obj = ureq->my_fd_obj; + THIS->my_fd = ureq->my_fd; + THIS->request_data = ureq->request_data; + free(ureq); + // current_thread = th_self(); + mt_lock(&interpreter_lock); + init_interpreter(); +#if __MAJOR__ == 7 && __MINOR__ < 1 + Pike_stack_top=((char *)&state)+ (thread_stack_size-16384) * STACK_DIRECTION; + recoveries = NULL; + thread_id = low_clone(thread_id_prog); + call_c_initializers(thread_id); + SWAP_OUT_THREAD(OBJ2THREAD(thread_id)); + OBJ2THREAD(thread_id)->swapped=0; + OBJ2THREAD(thread_id)->id=th_self(); + num_threads++; + thread_table_insert(thread_id); +#else + Pike_interpreter.stack_top=((char *)&state)+ (thread_stack_size-16384) * STACK_DIRECTION; + Pike_interpreter.recoveries = NULL; + Pike_interpreter.thread_id = low_clone(thread_id_prog); + call_c_initializers(Pike_interpreter.thread_id); + SWAP_OUT_THREAD(OBJ2THREAD(Pike_interpreter.thread_id)); + OBJ2THREAD(Pike_interpreter.thread_id)->swapped=0; + OBJ2THREAD(Pike_interpreter.thread_id)->id=th_self(); + num_threads++; + thread_table_insert(Pike_interpreter.thread_id); +#endif + + SG(request_info).query_string = lookup_string_header("QUERY_STRING", 0); + SG(server_context) = (void *)1; /* avoid server_context == NULL */ + + /* path_translated is apparently the absolute path to the file, not + the translated PATH_INFO + */ + SG(request_info).path_translated = + lookup_string_header("SCRIPT_FILENAME", NULL); + SG(request_info).request_uri = lookup_string_header("DOCUMENT_URI", NULL); + if(!SG(request_info).request_uri) + SG(request_info).request_uri = lookup_string_header("SCRIPT_NAME", NULL); + SG(request_info).request_method = lookup_string_header("REQUEST_METHOD", "GET"); + SG(request_info).content_length = lookup_integer_header("HTTP_CONTENT_LENGTH", 0); + SG(request_info).content_type = lookup_string_header("HTTP_CONTENT_TYPE", NULL); + SG(sapi_headers).http_response_code = 200; + if (!strcmp(SG(request_info).request_method, "HEAD")) { + SG(request_info).headers_only = 1; + } else { + SG(request_info).headers_only = 0; + } + + /* FIXME: Check for auth stuff needs to be fixed... */ + SG(request_info).auth_user = NULL; + SG(request_info).auth_password = NULL; + + /* Swap out this thread and release the interpreter lock to allow + * Pike threads to run. We wait since the above would otherwise require + * a lot of unlock/lock. + */ + SWAP_OUT_CURRENT_THREAD(); + mt_unlock(&interpreter_lock); + + +#ifdef VIRTUAL_DIR + /* Change virtual directory, if the feature is enabled, which is + * almost a requirement for PHP in Roxen. Might want to fail if it + * isn't. + */ + dir = malloc(len = THIS->filename->len); + strcpy(dir, THIS->filename->str); + while(--len >= 0 && dir[len] != '/') + ; + if(len > 0) { + dir[len] = '\0'; + } + V_CHDIR(dir); + free(dir); +#endif + + file_handle.type = ZEND_HANDLE_FILENAME; + file_handle.filename = THIS->filename->str; + file_handle.free_filename = 0; + + res = php_request_startup(CLS_C ELS_CC PLS_CC SLS_CC); + + if(res == FAILURE) { + THREAD_SAFE_RUN({ + apply_svalue(&THIS->done_cb, 0); + pop_stack(); + free_struct(SLS_C); + }, "Negative run response"); + } else { + THREAD_SAFE_RUN(php_caudium_hash_environment(CLS_C ELS_CC PLS_CC SLS_CC), + "environment hashing"); + php_execute_script(&file_handle CLS_CC ELS_CC PLS_CC); + php_request_shutdown(NULL); + THREAD_SAFE_RUN({ + apply_svalue(&THIS->done_cb, 0); + pop_stack(); + free_struct(SLS_C); + }, "positive run response"); + } + mt_lock(&interpreter_lock); + SWAP_IN_CURRENT_THREAD(); +#if __MAJOR__ == 7 && __MINOR__ < 1 + OBJ2THREAD(thread_id)->status=THREAD_EXITED; + co_signal(& OBJ2THREAD(thread_id)->status_change); + thread_table_delete(thread_id); + free_object(thread_id); + thread_id=NULL; +#else + OBJ2THREAD(Pike_interpreter.thread_id)->status=THREAD_EXITED; + co_signal(& OBJ2THREAD(Pike_interpreter.thread_id)->status_change); + thread_table_delete(Pike_interpreter.thread_id); + free_object(Pike_interpreter.thread_id); + Pike_interpreter.thread_id=NULL; +#endif + cleanup_interpret(); + num_threads--; + mt_unlock(&interpreter_lock); +} + +/* + * The php_caudium_request_handler() is called per request and handles + * everything for one request. + */ + +void f_php_caudium_request_handler(INT32 args) +{ + struct object *my_fd_obj; + struct mapping *request_data; + struct svalue *done_callback; + struct pike_string *script; + struct svalue *raw_fd; + struct pike_string *ind; + php_caudium_request *_request; + THIS = malloc(sizeof(php_caudium_request)); + if(THIS == NULL) + error("Out of memory."); + + // if(current_thread == th_self()) + // error("PHP4.Interpreter->run: Tried to run a PHP-script from a PHP " + // "callback!"); + get_all_args("PHP4.Interpreter->run", args, "%S%m%O%*", &script, + &request_data, &my_fd_obj, &done_callback); + if(done_callback->type != PIKE_T_FUNCTION) + error("PHP4.Interpreter->run: Bad argument 4, expected function.\n"); + add_ref(request_data); + add_ref(my_fd_obj); + add_ref(script); + + THIS->request_data = request_data; + THIS->my_fd_obj = my_fd_obj; + THIS->filename = script; + assign_svalue_no_free(&THIS->done_cb, done_callback); + + ind = make_shared_binary_string("my_fd", 5); + raw_fd = low_mapping_string_lookup(THIS->request_data, ind); + if(raw_fd && raw_fd->type == PIKE_T_OBJECT) + { + int fd = fd_from_object(raw_fd->u.object); + if(fd == -1) + error("PHP4.Interpreter->run: my_fd object not open or not an FD.\n"); + THIS->my_fd = fd; + } else + THIS->my_fd = 0; + th_farm((void (*)(void *))php_caudium_module_main, THIS); + + pop_n_elems(args); +} + +static void free_struct(SLS_D) +{ + GET_THIS(); + if(THIS->request_data) free_mapping(THIS->request_data); + if(THIS->my_fd_obj) free_object(THIS->my_fd_obj); + free_svalue(&THIS->done_cb); + if(THIS->filename) free_string(THIS->filename); + MEMSET(THIS, 0, sizeof(php_caudium_request)); +} + + +/* + * pike_module_init() is called by Pike once at startup + * + * This functions allocates basic structures + */ + +void pike_module_init( void ) +{ + if (!caudium_php_initialized) { +#ifdef ZTS + tsrm_startup(1, 1, 0); + caudium_globals_id = ts_allocate_id(sizeof(php_caudium_request), NULL, NULL); +#endif + sapi_startup(&sapi_module); + php_caudium_startup(&sapi_module); + caudium_php_initialized = 1; + PHP_INIT_LOCK(); + } + start_new_program(); /* Text */ + pike_add_function("run", f_php_caudium_request_handler, + "function(string,mapping,object,function:void)", 0); + add_program_constant("Interpreter", (php_program = end_program()), 0); +} + +/* + * pike_module_exit() performs the last steps before the + * server exists. Shutdowns basic services and frees memory + */ + +void pike_module_exit(void) +{ + caudium_php_initialized = 0; + sapi_module.shutdown(&sapi_module); + if(php_program) free_program(php_program); +#ifdef ZTS + tsrm_shutdown(); +#endif + PHP_DESTROY(); +} +#endif diff --git a/sapi/caudium/config.m4 b/sapi/caudium/config.m4 new file mode 100644 index 0000000000..ad8c8b6e31 --- /dev/null +++ b/sapi/caudium/config.m4 @@ -0,0 +1,50 @@ +dnl ## $Id$ -*- sh -*- + +RESULT=no +AC_MSG_CHECKING(for Caudium support) +AC_ARG_WITH(caudium, +[ --with-caudium=DIR Build PHP as a Pike module for use with Caudium + DIR is the Caudium server dir, with the default value + /usr/local/caudium/server.], +[ + if test ! -d $withval ; then + withval=/usr/local/caudium/server + fi + if test -f $withval/bin/caudium; then + PIKE="$withval/bin/caudium" + elif test -f $withval/bin/pike; then + PIKE="$withval/bin/pike" + else + AC_MSG_ERROR(Couldn't find a pike in $withval/bin/) + fi + if $PIKE -e 'float v; int rel;sscanf(version(), "Pike v%f release %d", v, rel);v += rel/10000.0; if(v < 7.0) exit(1); exit(0);'; then + PIKE_MODULE_DIR="`$PIKE --show-paths 2>&1| grep lib/modules | sed -e 's/.*: //'`" + PIKE_INCLUDE_DIR="`echo $PIKE_MODULE_DIR | sed -e 's,lib/pike/modules,include/pike,' -e 's,lib/modules,include/pike,'`" + if test -z "$PIKE_INCLUDE_DIR" -o -z "$PIKE_MODULE_DIR"; then + AC_MSG_ERROR(Failed to figure out Pike module and include directories) + fi + else + AC_MSG_ERROR(Caudium PHP4 requires Pike 7.0 or newer) + fi + PIKE_VERSION=`$PIKE -e 'string v; int rel;sscanf(version(), "Pike v%s release %d", v, rel); write(v+"."+rel);'` + AC_ADD_INCLUDE($PIKE_INCLUDE_DIR) + AC_DEFINE(HAVE_CAUDIUM,1,[Whether to compile with Caudium support]) + PHP_SAPI=caudium + PHP_BUILD_SHARED + INSTALL_IT="\$(INSTALL) -m 0755 $SAPI_SHARED $withval/lib/$PIKE_VERSION/PHP4.so" + RESULT="yes + *** Pike binary used: $PIKE + *** Pike include dir: $PIKE_INCLUDE_DIR + *** Pike version: $PIKE_VERSION" + PIKE_INCLUDE_DIR=" -I$PIKE_INCLUDE_DIR " +]) +AC_MSG_RESULT($RESULT) + +dnl Always use threads since thread-free support really blows. + +PHP_BUILD_THREAD_SAFE + +dnl ## Local Variables: +dnl ## tab-width: 4 +dnl ## End: +