Annotation of embedaddon/php/sapi/roxen/roxen.c, revision 1.1.1.4
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.4 ! misho 5: | Copyright (c) 1997-2014 The PHP Group |
1.1 misho 6: +----------------------------------------------------------------------+
7: | This source file is subject to version 3.01 of the PHP license, |
8: | that is bundled with this package in the file LICENSE, and is |
9: | available through the world-wide-web at the following url: |
10: | http://www.php.net/license/3_01.txt |
11: | If you did not receive a copy of the PHP license and are unable to |
12: | obtain it through the world-wide-web, please send a note to |
13: | license@php.net so we can mail you a copy immediately. |
14: +----------------------------------------------------------------------+
15: | Author: David Hedbor <neotron@php.net> |
16: | Based on aolserver SAPI by Sascha Schumann <sascha@schumann.cx> |
17: +----------------------------------------------------------------------+
18: */
19:
1.1.1.2 misho 20: /* $Id$ */
1.1 misho 21:
22: #include "php.h"
23: #ifdef HAVE_ROXEN
24:
25: #include "php_ini.h"
26: #include "php_globals.h"
27: #include "SAPI.h"
28: #include "php_main.h"
29: #include "ext/standard/info.h"
30:
31: #include "php_version.h"
32:
33: #ifndef ZTS
34: /* Only valid if thread safety is enabled. */
35: #undef ROXEN_USE_ZTS
36: #endif
37:
38:
39: /* Pike Include Files
40: *
41: * conflicts with pike avoided by only using long names. Requires a new
42: * Pike 0.7 since it was implemented for this interface only.
43: *
44: */
45: #define NO_PIKE_SHORTHAND
46:
47: #include <fdlib.h>
48: #include <program.h>
49: #include <pike_types.h>
50: #include <interpret.h>
51: #include <module_support.h>
52: #include <error.h>
53: #include <array.h>
54: #include <backend.h>
55: #include <stralloc.h>
56: #include <mapping.h>
57: #include <object.h>
58: #include <threads.h>
59: #include <builtin_functions.h>
60: #include <operators.h>
61:
62: #undef HIDE_GLOBAL_VARIABLES
63: #undef REVEAL_GLOBAL_VARIABLES
64: #define HIDE_GLOBAL_VARIABLES()
65: #define REVEAL_GLOBAL_VARIABLES()
66:
67: /* php_roxen_request is per-request object storage */
68:
69: typedef struct
70: {
71: struct mapping *request_data;
72: struct object *my_fd_obj;
73: int my_fd;
74: char *filename;
75: } php_roxen_request;
76:
77:
78: /* Defines to get to the data supplied when the script is started. */
79:
80: #ifdef ROXEN_USE_ZTS
81:
82: /* ZTS does work now, but it seems like it's faster using the "serialization"
83: * method I previously used. Thus it's not used unless ROXEN_USE_ZTS is defined.
84: */
85:
86: /* Per thread storage area id... */
87: static int roxen_globals_id;
88:
89: # define GET_THIS() php_roxen_request *_request = ts_resource(roxen_globals_id)
90: # define THIS _request
91: #else
92: static php_roxen_request *current_request = NULL;
93:
94: # define GET_THIS() current_request = ((php_roxen_request *)Pike_fp->current_storage)
95: # define THIS current_request
96: #endif
97:
98: /* File descriptor integer. Used to write directly to the FD without
99: * passing Pike
100: */
101: #define MY_FD (THIS->my_fd)
102:
103: /* FD object. Really a PHPScript object from Pike which implements a couple
104: * of functions to handle headers, writing and buffering.
105: */
106: #define MY_FD_OBJ ((struct object *)(THIS->my_fd_obj))
107:
108: /* Mapping with data supplied from the calling Roxen module. Contains
109: * a mapping with headers, an FD object etc.
110: */
111: #define REQUEST_DATA ((struct mapping *)(THIS->request_data))
112:
113:
114: #if defined(_REENTRANT) && !defined(ROXEN_USE_ZTS)
115: /* Lock used to serialize the PHP execution. If ROXEN_USE_ZTS is defined, we
116: * are using the PHP thread safe mechanism instead.
117: */
118: static PIKE_MUTEX_T roxen_php_execution_lock;
119: # define PHP_INIT_LOCK() mt_init(&roxen_php_execution_lock)
120: # define PHP_LOCK(X) THREADS_ALLOW();mt_lock(&roxen_php_execution_lock);THREADS_DISALLOW()
121: # define PHP_UNLOCK(X) mt_unlock(&roxen_php_execution_lock);
122: # define PHP_DESTROY() mt_destroy(&roxen_php_execution_lock)
123: #else /* !_REENTRANT */
124: # define PHP_INIT_LOCK()
125: # define PHP_LOCK(X)
126: # define PHP_UNLOCK(X)
127: # define PHP_DESTROY()
128: #endif /* _REENTRANT */
129:
130: extern int fd_from_object(struct object *o);
131: static unsigned char roxen_php_initialized;
132:
133: /* This allows calling of pike functions from the PHP callbacks,
134: * which requires the Pike interpreter to be locked.
135: */
136: #define THREAD_SAFE_RUN(COMMAND, what) do {\
137: struct thread_state *state;\
138: if((state = thread_state_for_id(th_self()))!=NULL) {\
139: if(!state->swapped) {\
140: COMMAND;\
141: } else {\
142: mt_lock(&interpreter_lock);\
143: SWAP_IN_THREAD(state);\
144: COMMAND;\
145: SWAP_OUT_THREAD(state);\
146: mt_unlock(&interpreter_lock);\
147: }\
148: }\
149: } while(0)
150:
151: struct program *php_program;
152:
153:
154: /* To avoid executing a PHP script from a PHP callback, which would
155: * create a deadlock, a global thread id is used. If the thread calling the
156: * php-script is the same as the current thread, it fails.
157: */
158: static int current_thread = -1;
159:
160:
161: /* Low level header lookup. Basically looks for the named header in the mapping
162: * headers in the supplied options mapping.
163: */
164:
165: static INLINE struct svalue *lookup_header(char *headername)
166: {
167: struct svalue *headers, *value;
168: struct pike_string *sind;
169: #ifdef ROXEN_USE_ZTS
170: GET_THIS();
171: #endif
172: sind = make_shared_string("env");
173: headers = low_mapping_string_lookup(REQUEST_DATA, sind);
174: free_string(sind);
175: if(!headers || headers->type != PIKE_T_MAPPING) return NULL;
176: sind = make_shared_string(headername);
177: value = low_mapping_string_lookup(headers->u.mapping, sind);
178: free_string(sind);
179: if(!value) return NULL;
180: return value;
181: }
182:
183: /* Lookup a header in the mapping and return the value as a string, or
184: * return the default if it's missing
185: */
186: INLINE static char *lookup_string_header(char *headername, char *default_value)
187: {
188: struct svalue *head = NULL;
189: THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup");
190: if(!head || head->type != PIKE_T_STRING)
191: return default_value;
192: return head->u.string->str;
193: }
194:
195: /* Lookup a header in the mapping and return the value as if it's an integer
196: * and otherwise return the default.
197: */
198: INLINE static int lookup_integer_header(char *headername, int default_value)
199: {
200: struct svalue *head = NULL;
201: THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup");
202: if(!head || head->type != PIKE_T_INT)
203: return default_value;
204: return head->u.integer;
205: }
206:
207: /*
208: * php_roxen_low_ub_write() writes data to the client connection. Might be
209: * rewritten to do more direct IO to save CPU and the need to lock the *
210: * interpreter for better threading.
211: */
212:
213: static int
214: php_roxen_low_ub_write(const char *str, uint str_length TSRMLS_DC) {
215: int sent_bytes = 0;
216: struct pike_string *to_write = NULL;
217: #ifdef ROXEN_USE_ZTS
218: GET_THIS();
219: #endif
220:
221: if(!MY_FD_OBJ->prog) {
222: PG(connection_status) = PHP_CONNECTION_ABORTED;
223: zend_bailout();
224: return -1;
225: }
226: to_write = make_shared_binary_string(str, str_length);
227: push_string(to_write);
228: safe_apply(MY_FD_OBJ, "write", 1);
229: if(Pike_sp[-1].type == PIKE_T_INT)
230: sent_bytes = Pike_sp[-1].u.integer;
231: pop_stack();
232: if(sent_bytes != str_length) {
233: /* This means the connection is closed. Dead. Gone. *sniff* */
234: php_handle_aborted_connection();
235: }
236: return sent_bytes;
237: }
238:
239: /*
240: * php_roxen_sapi_ub_write() calls php_roxen_low_ub_write in a Pike thread
241: * safe manner.
242: */
243:
244: static int
245: php_roxen_sapi_ub_write(const char *str, uint str_length TSRMLS_DC)
246: {
247: #ifdef ROXEN_USE_ZTS
248: GET_THIS();
249: #endif
250:
251: int sent_bytes = 0, fd = MY_FD;
252: if(fd)
253: {
254: for(sent_bytes=0;sent_bytes < str_length;)
255: {
256: int written;
257: written = fd_write(fd, str + sent_bytes, str_length - sent_bytes);
258: if(written < 0)
259: {
260: switch(errno)
261: {
262: default:
263: /* This means the connection is closed. Dead. Gone. *sniff* */
264: PG(connection_status) = PHP_CONNECTION_ABORTED;
265: zend_bailout();
266: return sent_bytes;
267: case EINTR:
268: case EWOULDBLOCK:
269: continue;
270: }
271:
272: } else {
273: sent_bytes += written;
274: }
275: }
276: } else {
277: THREAD_SAFE_RUN(sent_bytes = php_roxen_low_ub_write(str, str_length TSRMLS_CC),
278: "write");
279: }
280: return sent_bytes;
281: }
282:
283: /* php_roxen_set_header() sets a header in the header mapping. Called in a
284: * thread safe manner from php_roxen_sapi_header_handler.
285: */
286: static void php_roxen_set_header(char *header_name, char *value, char *p)
287: {
288: struct svalue hsval;
289: struct pike_string *hval, *ind, *hind;
290: struct mapping *headermap;
291: struct svalue *s_headermap;
292: #ifdef ROXEN_USE_ZTS
293: GET_THIS();
294: #endif
295: hval = make_shared_string(value);
296: ind = make_shared_string(" _headers");
297: hind = make_shared_binary_string(header_name,
298: (int)(p - header_name));
299:
300: s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind);
301: if(!s_headermap)
302: {
303: struct svalue mappie;
304: mappie.type = PIKE_T_MAPPING;
305: headermap = allocate_mapping(1);
306: mappie.u.mapping = headermap;
307: mapping_string_insert(REQUEST_DATA, ind, &mappie);
308: free_mapping(headermap);
309: } else
310: headermap = s_headermap->u.mapping;
311:
312: hsval.type = PIKE_T_STRING;
313: hsval.u.string = hval;
314: mapping_string_insert(headermap, hind, &hsval);
315:
316: free_string(hval);
317: free_string(ind);
318: free_string(hind);
319: }
320:
321: /*
322: * php_roxen_sapi_header_handler() sets a HTTP reply header to be
323: * sent to the client.
324: */
325: static int
326: php_roxen_sapi_header_handler(sapi_header_struct *sapi_header,
327: sapi_headers_struct *sapi_headers TSRMLS_DC)
328: {
329: char *header_name, *header_content, *p;
330: header_name = sapi_header->header;
331: header_content = p = strchr(header_name, ':');
332:
333: if(p) {
334: do {
335: header_content++;
336: } while(*header_content == ' ');
337: THREAD_SAFE_RUN(php_roxen_set_header(header_name, header_content, p), "header handler");
338: }
339: sapi_free_header(sapi_header);
340: return 0;
341: }
342:
343: /*
344: * php_roxen_sapi_send_headers() flushes the headers to the client.
345: * Called before real content is sent by PHP.
346: */
347:
348: static int
349: php_roxen_low_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
350: {
351: struct pike_string *ind;
352: struct svalue *s_headermap;
353: #ifdef ROXEN_USE_ZTS
354: GET_THIS();
355: #endif
356:
357: if(!MY_FD_OBJ->prog) {
358: PG(connection_status) = PHP_CONNECTION_ABORTED;
359: zend_bailout();
360: return SAPI_HEADER_SEND_FAILED;
361: }
362: ind = make_shared_string(" _headers");
363: s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind);
364: free_string(ind);
365:
366: push_int(SG(sapi_headers).http_response_code);
367: if(s_headermap && s_headermap->type == PIKE_T_MAPPING)
368: ref_push_mapping(s_headermap->u.mapping);
369: else
370: push_int(0);
371: safe_apply(MY_FD_OBJ, "send_headers", 2);
372: pop_stack();
373:
374: return SAPI_HEADER_SENT_SUCCESSFULLY;
375: }
376:
377: static int
378: php_roxen_sapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
379: {
380: int res = 0;
381: THREAD_SAFE_RUN(res = php_roxen_low_send_headers(sapi_headers TSRMLS_CC), "send headers");
382: return res;
383: }
384:
385: /*
386: * php_roxen_sapi_read_post() reads a specified number of bytes from
387: * the client. Used for POST/PUT requests.
388: */
389:
390: INLINE static int php_roxen_low_read_post(char *buf, uint count_bytes)
391: {
392: uint total_read = 0;
393: #ifdef ROXEN_USE_ZTS
394: GET_THIS();
395: #endif
396: TSRMLS_FETCH();
397:
398: if(!MY_FD_OBJ->prog)
399: {
400: PG(connection_status) = PHP_CONNECTION_ABORTED;
401: zend_bailout();
402: return -1;
403: }
404: push_int(count_bytes);
405: safe_apply(MY_FD_OBJ, "read_post", 1);
406: if(Pike_sp[-1].type == PIKE_T_STRING) {
407: MEMCPY(buf, Pike_sp[-1].u.string->str,
408: (total_read = Pike_sp[-1].u.string->len));
409: buf[total_read] = '\0';
410: } else
411: total_read = 0;
412: pop_stack();
413: return total_read;
414: }
415:
416: static int
417: php_roxen_sapi_read_post(char *buf, uint count_bytes TSRMLS_DC)
418: {
419: uint total_read = 0;
420: THREAD_SAFE_RUN(total_read = php_roxen_low_read_post(buf, count_bytes), "read post");
421: return total_read;
422: }
423:
424: /*
425: * php_roxen_sapi_read_cookies() returns the Cookie header from
426: * the HTTP request header
427: */
428:
429: static char *
430: php_roxen_sapi_read_cookies(TSRMLS_D)
431: {
432: char *cookies;
433: cookies = lookup_string_header("HTTP_COOKIE", NULL);
434: return cookies;
435: }
436:
437: static void php_info_roxen(ZEND_MODULE_INFO_FUNC_ARGS)
438: {
439: /* char buf[512]; */
440: php_info_print_table_start();
1.1.1.2 misho 441: php_info_print_table_row(2, "SAPI module version", "$Id$");
1.1 misho 442: /* php_info_print_table_row(2, "Build date", Ns_InfoBuildDate());
443: php_info_print_table_row(2, "Config file path", Ns_InfoConfigFile());
444: php_info_print_table_row(2, "Error Log path", Ns_InfoErrorLog());
445: php_info_print_table_row(2, "Installation path", Ns_InfoHomePath());
446: php_info_print_table_row(2, "Hostname of server", Ns_InfoHostname());
447: php_info_print_table_row(2, "Source code label", Ns_InfoLabel());
448: php_info_print_table_row(2, "Server platform", Ns_InfoPlatform());
449: snprintf(buf, 511, "%s/%s", Ns_InfoServerName(), Ns_InfoServerVersion());
450: php_info_print_table_row(2, "Server version", buf);
451: snprintf(buf, 511, "%d day(s), %02d:%02d:%02d",
452: uptime / 86400,
453: (uptime / 3600) % 24,
454: (uptime / 60) % 60,
455: uptime % 60);
456: php_info_print_table_row(2, "Server uptime", buf);
457: */
458: php_info_print_table_end();
459: }
460:
461: static zend_module_entry php_roxen_module = {
462: STANDARD_MODULE_HEADER,
463: "Roxen",
464: NULL,
465: NULL,
466: NULL,
467: NULL,
468: NULL,
469: php_info_roxen,
470: NULL,
471: STANDARD_MODULE_PROPERTIES
472: };
473:
474: static int php_roxen_startup(sapi_module_struct *sapi_module)
475: {
476: if(php_module_startup(sapi_module, &php_roxen_module, 1) == FAILURE) {
477: return FAILURE;
478: } else {
479: return SUCCESS;
480: }
481: }
482:
483: /* this structure is static (as in "it does not change") */
484:
485: static sapi_module_struct roxen_sapi_module = {
486: "roxen",
487: "Roxen",
488: php_roxen_startup, /* startup */
489: php_module_shutdown_wrapper, /* shutdown */
490: NULL, /* activate */
491: NULL, /* deactivate */
492: php_roxen_sapi_ub_write, /* unbuffered write */
493: NULL, /* flush */
494: NULL, /* get uid */
495: NULL, /* getenv */
496: php_error, /* error handler */
497: php_roxen_sapi_header_handler, /* header handler */
498: php_roxen_sapi_send_headers, /* send headers handler */
499: NULL, /* send header handler */
500: php_roxen_sapi_read_post, /* read POST data */
501: php_roxen_sapi_read_cookies, /* read Cookies */
502: NULL, /* register server variables */
503: NULL, /* Log message */
504: NULL, /* Get request time */
505: NULL, /* Child terminate */
506:
507: STANDARD_SAPI_MODULE_PROPERTIES
508: };
509:
510: /*
511: * php_roxen_hash_environment() populates the php script environment
512: * with a number of variables. HTTP_* variables are created for
513: * the HTTP header data, so that a script can access these.
514: */
515: #define ADD_STRING(name) \
516: MAKE_STD_ZVAL(zvalue); \
517: zvalue->type = IS_STRING; \
518: zvalue->value.str.len = strlen(buf); \
519: zvalue->value.str.val = estrndup(buf, zvalue->value.str.len); \
520: zend_hash_update(&EG(symbol_table), name, sizeof(name), \
521: &zvalue, sizeof(zval *), NULL)
522:
523: static void
524: php_roxen_hash_environment(TSRMLS_D)
525: {
526: int i;
527: char buf[512];
528: zval *zvalue;
529: struct svalue *headers;
530: struct pike_string *sind;
531: struct array *indices;
532: struct svalue *ind, *val;
533: #ifdef ROXEN_USE_ZTS
534: GET_THIS();
535: #endif
536: sind = make_shared_string("env");
537: headers = low_mapping_string_lookup(REQUEST_DATA, sind);
538: free_string(sind);
539: if(headers && headers->type == PIKE_T_MAPPING) {
540: indices = mapping_indices(headers->u.mapping);
541: for(i = 0; i < indices->size; i++) {
542: ind = &indices->item[i];
543: val = low_mapping_lookup(headers->u.mapping, ind);
544: if(ind && ind->type == PIKE_T_STRING &&
545: val && val->type == PIKE_T_STRING) {
546: int buf_len;
547: buf_len = MIN(511, ind->u.string->len);
548: strncpy(buf, ind->u.string->str, buf_len);
549: buf[buf_len] = '\0'; /* Terminate correctly */
550: MAKE_STD_ZVAL(zvalue);
551: zvalue->type = IS_STRING;
552: zvalue->value.str.len = val->u.string->len;
553: zvalue->value.str.val = estrndup(val->u.string->str, zvalue->value.str.len);
554:
555: zend_hash_update(&EG(symbol_table), buf, buf_len + 1, &zvalue, sizeof(zval *), NULL);
556: }
557: }
558: free_array(indices);
559: }
560:
561: /*
562: MAKE_STD_ZVAL(zvalue);
563: zvalue->type = IS_LONG;
564: zvalue->value.lval = Ns_InfoBootTime();
565: zend_hash_update(&EG(symbol_table), "SERVER_BOOTTIME", sizeof("SERVER_BOOTTIME"), &zvalue, sizeof(zval *), NULL);
566: */
567: }
568:
569: /*
570: * php_roxen_module_main() is called by the per-request handler and
571: * "executes" the script
572: */
573:
574: static int php_roxen_module_main(TSRMLS_D)
575: {
576: int res, len;
577: char *dir;
578: zend_file_handle file_handle;
579: #ifdef ROXEN_USE_ZTS
580: GET_THIS();
581: #endif
582:
583: file_handle.type = ZEND_HANDLE_FILENAME;
584: file_handle.filename = THIS->filename;
585: file_handle.free_filename = 0;
586: file_handle.opened_path = NULL;
587:
588: THREADS_ALLOW();
589: res = php_request_startup(TSRMLS_C);
590: THREADS_DISALLOW();
591: if(res == FAILURE) {
592: return 0;
593: }
594: php_roxen_hash_environment(TSRMLS_C);
595: THREADS_ALLOW();
596: php_execute_script(&file_handle TSRMLS_CC);
597: php_request_shutdown(NULL);
598: THREADS_DISALLOW();
599: return 1;
600: }
601:
602: /*
603: * The php_roxen_request_handler() is called per request and handles
604: * everything for one request.
605: */
606:
607: void f_php_roxen_request_handler(INT32 args)
608: {
609: struct object *my_fd_obj;
610: struct mapping *request_data;
611: struct svalue *done_callback, *raw_fd;
612: struct pike_string *script, *ind;
613: int status = 1;
614: #ifdef ROXEN_USE_ZTS
615: GET_THIS();
616: #endif
617: TSRMLS_FETCH();
618:
619: if(current_thread == th_self())
620: php_error(E_WARNING, "PHP5.Interpreter->run: Tried to run a PHP-script from a PHP "
621: "callback!");
622: get_all_args("PHP5.Interpreter->run", args, "%S%m%O%*", &script,
623: &request_data, &my_fd_obj, &done_callback);
624: if(done_callback->type != PIKE_T_FUNCTION)
625: php_error(E_WARNING, "PHP5.Interpreter->run: Bad argument 4, expected function.\n");
626: PHP_LOCK(THIS); /* Need to lock here or reusing the same object might cause
627: * problems in changing stuff in that object */
628: #ifndef ROXEN_USE_ZTS
629: GET_THIS();
630: #endif
631: THIS->request_data = request_data;
632: THIS->my_fd_obj = my_fd_obj;
633: THIS->filename = script->str;
634: current_thread = th_self();
635: SG(request_info).query_string = lookup_string_header("QUERY_STRING", 0);
636: SG(server_context) = (void *)1; /* avoid server_context == NULL */
637:
638: /* path_translated is apparently the absolute path to the file, not
639: the translated PATH_INFO
640: */
641: SG(request_info).path_translated =
642: lookup_string_header("SCRIPT_FILENAME", NULL);
643: SG(request_info).request_uri = lookup_string_header("DOCUMENT_URI", NULL);
644: if(!SG(request_info).request_uri)
645: SG(request_info).request_uri = lookup_string_header("SCRIPT_NAME", NULL);
646: SG(request_info).request_method = lookup_string_header("REQUEST_METHOD", "GET");
647: SG(request_info).content_length = lookup_integer_header("HTTP_CONTENT_LENGTH", 0);
648: SG(request_info).content_type = lookup_string_header("HTTP_CONTENT_TYPE", NULL);
649: SG(sapi_headers).http_response_code = 200;
650:
651: /* FIXME: Check for auth stuff needs to be fixed... */
652: SG(request_info).auth_user = NULL;
653: SG(request_info).auth_password = NULL;
654:
655: ind = make_shared_binary_string("my_fd", 5);
656: raw_fd = low_mapping_string_lookup(THIS->request_data, ind);
657: if(raw_fd && raw_fd->type == PIKE_T_OBJECT)
658: {
659: int fd = fd_from_object(raw_fd->u.object);
660: if(fd == -1)
661: php_error(E_WARNING, "PHP5.Interpreter->run: my_fd object not open or not an FD.\n");
662: THIS->my_fd = fd;
663: } else
664: THIS->my_fd = 0;
665:
666: status = php_roxen_module_main(TSRMLS_C);
667: current_thread = -1;
668:
669: apply_svalue(done_callback, 0);
670: pop_stack();
671: pop_n_elems(args);
672: push_int(status);
673: PHP_UNLOCK(THIS);
674: }
675:
676:
677: /* Clear the object global struct */
678: static void clear_struct(struct object *o)
679: {
680: MEMSET(Pike_fp->current_storage, 0, sizeof(php_roxen_request));
681: }
682:
683:
684: /*
685: * pike_module_init() is called by Pike once at startup
686: *
687: * This functions allocates basic structures
688: */
689:
690: void pike_module_init( void )
691: {
692: if (!roxen_php_initialized) {
693: #ifdef ZTS
694: tsrm_startup(1, 1, 0, NULL);
695: #ifdef ROXEN_USE_ZTS
696: ts_allocate_id(&roxen_globals_id, sizeof(php_roxen_request), NULL, NULL);
697: #endif
698: #endif
699: sapi_startup(&roxen_sapi_module);
700: /*php_roxen_startup(&roxen_sapi_module); removed - should be called from SAPI activation*/
701: roxen_php_initialized = 1;
702: PHP_INIT_LOCK();
703: }
704: start_new_program(); /* Text */
705: ADD_STORAGE(php_roxen_request);
706: set_init_callback(clear_struct);
707: pike_add_function("run", f_php_roxen_request_handler,
708: "function(string, mapping, object, function:int)", 0);
709: add_program_constant("Interpreter", (php_program = end_program()), 0);
710: }
711:
712: /*
713: * pike_module_exit() performs the last steps before the
714: * server exists. Shutdowns basic services and frees memory
715: */
716:
717: void pike_module_exit(void)
718: {
719: roxen_php_initialized = 0;
720: roxen_sapi_module.shutdown(&roxen_sapi_module);
721: if(php_program) free_program(php_program);
722: #ifdef ZTS
723: tsrm_shutdown();
724: #endif
725: PHP_DESTROY();
726: }
727: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>