#include "php_version.h"
+
+#ifdef ZTS
+/* This is true at the moment. It works with a Roxen with threads. As a matter
+ * of fact, that is preferred. However the scripts are executed once at a time.
+ * Once PHP is threadsafe it should be easy enough to fix.
+ */
+#error Roxen PHP module isnt thread safe at the moment.
+#endif
+
+
/* 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
-#ifdef ZTS
-#error Roxen PHP module isnt thread safe at the moment.
-#endif
#include <fdlib.h>
#include <program.h>
#include <operators.h>
#ifdef _REENTRANT
+/* Lock used to serialize the PHP execution */
static PIKE_MUTEX_T roxen_php_execution_lock;
#define PHP_INIT_LOCK() mt_init(&roxen_php_execution_lock)
-#define PHP_LOCK() fprintf(stderr, "*** php lock.\n");THREADS_ALLOW();mt_lock(&roxen_php_execution_lock);fprintf(stderr, "*** php locked.\n");THREADS_DISALLOW()
-#define PHP_UNLOCK() mt_unlock(&roxen_php_execution_lock);fprintf(stderr, "*** php unlocked.\n");
+#define PHP_LOCK() fprintf(stderr, "*** php lock (thr_id=%d, glob=%d).\n", th_self(), current_thread);THREADS_ALLOW();mt_lock(&roxen_php_execution_lock);fprintf(stderr, "*** php locked.\n");THREADS_DISALLOW()
+#define PHP_UNLOCK() mt_unlock(&roxen_php_execution_lock);fprintf(stderr, "*** php unlocked (thr_id=%d, glob=%d).\n", th_self(), current_thread);
#define PHP_DESTROY() mt_destroy(&roxen_php_execution_lock)
#else /* !_REENTRANT */
#define PHP_INIT_LOCK()
extern int fd_from_object(struct object *o);
static unsigned char roxen_php_initialized;
+/* Defines to get to the data supplied when the script is started. */
#define REALTHIS ((php_roxen_request *)fp->current_storage)
#define GET_THIS() current_request = REALTHIS
#define THIS current_request
#define MY_FD ((struct object *)(THIS->my_fd))
#define REQUEST_DATA ((struct mapping *)(THIS->request_data))
+/* This allows calling of pike functions from the PHP callbacks,
+ * which requires the Pike interpretor to be locked.
+ */
#define THREAD_SAFE_RUN(COMMAND, what) do {\
struct thread_state *state;\
fprintf(stderr,"threads: %d disabled: %d id: %d\n",num_threads, threads_disabled, th_self());\
}\
} while(0)
+/* Toggle debug printouts, for now... */
+//#define MUCH_DEBUG
#ifndef MUCH_DEBUG
void no_fprintf(){}
#define fprintf no_fprintf
#endif
-/* php_roxen_context is per-server (thus only once at all) */
-
struct program *php_program;
-/* roxen_globals_struct is per-request */
-
+/* roxen_globals_struct is per-request object storage */
typedef struct {
struct mapping *request_data;
struct object *my_fd;
} php_roxen_request;
static php_roxen_request *current_request = NULL;
+
+/* 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;
-INLINE struct svalue *lookup_header(char *headername)
+
+/* Low level header lookup. Basically looks for the named header in the mapping
+ * headers in the supplied options mapping.
+ */
+
+static INLINE struct svalue *lookup_header(char *headername)
{
struct svalue *headers, *value;
struct pike_string *sind;
/* Lookup a header in the mapping and return the value as a string, or
* return the default if it's missing
*/
-INLINE char *lookup_string_header(char *headername, char *default_value)
+INLINE static char *lookup_string_header(char *headername, char *default_value)
{
struct svalue *head;
THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup");
/* Lookup a header in the mapping and return the value as if it's an integer
* and otherwise return the default.
*/
-INLINE int lookup_integer_header(char *headername, int default_value)
+INLINE static int lookup_integer_header(char *headername, int default_value)
{
struct svalue *head;
THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup");
}
/*
- * php_roxen_low_ub_write() writes data to the client connection.
+ * php_roxen_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 *
+ * interpretor for better threading.
*/
static int
return sent_bytes;
}
-/* php_roxen_set_header() sets a header in the header mapping.
- Set Header
-*/
+/* php_roxen_set_header() sets a header in the header mapping. Called in a
+ * thread safe manner from php_roxen_sapi_header_handler.
+ */
static void php_roxen_set_header(char *header_name, char *value, char *p)
{
struct svalue hsval;
* php_roxen_sapi_header_handler() sets a HTTP reply header to be
* sent to the client.
*/
-
static int
-php_roxen_sapi_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers SLS_DC)
+php_roxen_sapi_header_handler(sapi_header_struct *sapi_header,
+ sapi_headers_struct *sapi_headers SLS_DC)
{
char *header_name, *header_content;
char *p;
* "executes" the script
*/
-int php_roxen_module_main(SLS_D)
+static int php_roxen_module_main(SLS_D)
{
zend_file_handle file_handle;
file_handle.type = ZEND_HANDLE_FILENAME;
return 1;
}
-/*
- * php_roxen_request_ctor() initializes the per-request data structure
- * and fills it with data provided by the web server
- */
-
-static void
-php_roxen_request_ctor(SLS_D)
-{
- char *server;
- char *root;
- int index;
- char *tmp;
-
- SG(request_info).auth_user = NULL;
- SG(request_info).auth_password = NULL;
- /*
- tmp = Ns_ConnAuthPasswd(NSG(conn));
- if(tmp) {
- tmp = estrdup(tmp);
- }
- SG(request_info).auth_password = tmp;
-
- NSG(data_avail) = SG(request_info).content_length;
- */
-}
-
-/*
- * php_roxen_request_dtor() destroys all data associated with
- * the per-request structure
- */
-
-static void
-php_roxen_request_dtor(SLS_D)
-{
- // free(SG(request_info).path_translated);
-}
-
/*
* The php_roxen_request_handler() is called per request and handles
* everything for one request.
SG(request_info).auth_user = NULL;
SG(request_info).auth_password = NULL;
status = php_roxen_module_main(SLS_C);
-
- php_roxen_request_dtor(SLS_C);
current_thread = -1;
PHP_UNLOCK();
}
-void clear_struct(struct object *o)
+static void clear_struct(struct object *o)
{
MEMSET(fp->current_storage, 0, sizeof(php_roxen_request));
}