Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

trying out shared resources, see SocketServer.php

  • Loading branch information...
commit d4d17504b244604205c05f84d0907e92d9ae4942 1 parent 58a4a10
Joe Watkins authored
2  config.m4
View
@@ -8,7 +8,7 @@ if test "$PHP_PTHREADS" != "no"; then
else
AC_MSG_ERROR([pthreads requires ZTS, please re-compile PHP with ZTS enabled])
fi
- PHP_NEW_EXTENSION(pthreads, php_pthreads.c src/lock.c src/globals.c src/prepare.c src/synchro.c src/state.c src/store.c src/modifiers.c src/handlers.c src/object.c, $ext_shared)
+ PHP_NEW_EXTENSION(pthreads, php_pthreads.c src/lock.c src/globals.c src/prepare.c src/synchro.c src/state.c src/store.c src/resources.c src/modifiers.c src/handlers.c src/object.c, $ext_shared)
PHP_ADD_BUILD_DIR($ext_builddir/src, 1)
PHP_ADD_INCLUDE($ext_builddir)
PHP_SUBST(PTHREADS_SHARED_LIBADD)
4 config.w32
View
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
PTHREADS_EXT_NAME="pthreads";
-PTHREADS_EXT_SRC="lock.c globals.c prepare.c synchro.c state.c store.c modifiers.c handlers.c object.c";
+PTHREADS_EXT_SRC="lock.c globals.c prepare.c synchro.c state.c store.c resources.c modifiers.c handlers.c object.c";
PTHREADS_EXT_DIR="ext/pthreads/src";
PTHREADS_EXT_API="php_pthreads.c";
PTHREADS_EXT_FLAGS="/I" + configure_module_dirname;
@@ -32,4 +32,4 @@ if (PHP_PTHREADS != "no") {
PTHREADS_EXT_SRC,
PTHREADS_EXT_NAME
);
-}
+}
3  examples/Pooling.php
View
@@ -113,4 +113,5 @@ public function shutdown() {
printf("Average processing time of %f seconds per task\n", $runtime/$attempts);
printf("---------------------------------------------------------\n");
if ($_SERVER["HTTP_HOST"]) echo "</pre>";
-?>
+profiler_output(sprintf("/tmp/callgrind.%d", zend_thread_id()));
+?>
2  examples/SimpleWebRequest.php
View
@@ -34,4 +34,4 @@ public function run(){
} else printf(" and %f seconds to finish, request failed\n", microtime(true)-$t);
}
-?>
+?>
80 examples/SocketServer.php
View
@@ -0,0 +1,80 @@
+<?php
+/*
+* @NOTE
+* RESOURCES ARE BEING TRIED OUT, THIS MAY CRASH OR KILL THE EXECUTOR OF THE SCRIPT: NOT MY FAULT
+*
+* It's pretty clear that people want resources to work, and I cannot deny it would be useful.
+* Officially, resources are unsupported, if it doesn't work there is NOTHING I can do about it.
+* I do NOT have the time to make every kind of resource safe, or ensure compatibility.
+* I can apply some cleverness to make sure resources are destroyed by whoever creates them, that is ALL.
+* In the case of sockets, this appears to work, the code below ran all day on pthreads.org without interruption.
+* AGAIN: If this does not work, there is NOTHING more I can do.
+ If a particular type of resource wigs out, there is NOTHING I can do.
+ If this kills you, horribly, there is NOTHING I can do.
+*/
+class Client extends Thread {
+ public function __construct($socket){
+ $this->socket = $socket;
+ $this->start();
+ }
+ public function run(){
+ $client = $this->socket;
+ if ($client) {
+ $header = 0;
+ while(($chars = socket_read($client, 1024, PHP_NORMAL_READ))) {
+ $head[$header]=trim($chars);
+ if ($header>0) {
+ if (!$head[$header] && !$head[$header-1])
+ break;
+ }
+ $header++;
+ }
+ foreach($head as $header) {
+ if ($header) {
+ $headers[]=$header;
+ }
+ }
+
+ $response = array(
+ "head" => array(
+ "HTTP/1.0 200 OK",
+ "Content-Type: text/html"
+ ),
+ "body" => array()
+ );
+
+ socket_getpeername($client, $address, $port);
+
+ $response["body"][]="<html>";
+ $response["body"][]="<head>";
+ $response["body"][]="<title>Multithread Sockets PHP ({$address}:{$port})</title>";
+ $response["body"][]="</head>";
+ $response["body"][]="<body>";
+ $response["body"][]="<pre>";
+ foreach($headers as $header)
+ $response["body"][]="{$header}";
+ $response["body"][]="</pre>";
+ $response["body"][]="</body>";
+ $response["body"][]="</html>";
+ $response["body"] = implode("\r\n", $response["body"]);
+ $response["head"][] = sprintf("Content-Length: %d", strlen($response["body"]));
+ $response["head"] = implode("\r\n", $response["head"]);
+
+ socket_write($client, $response["head"]);
+ socket_write($client, "\r\n\r\n");
+ socket_write($client, $response["body"]);
+
+ socket_close($client);
+ }
+ }
+}
+/* ladies and gentlemen, the world first multi-threaded socket server in PHP :) */
+$server = socket_create_listen(10000);
+while(($client = socket_accept($server))){
+ new Client($client);
+ /* in the real world, do something here to ensure clients not running are destroyed */
+ /* the nature of a socket server is an endless loop,
+ if you do not do something to explicitly destroy clients you create this may leak */
+}
+/* that is all */
+?>
1  src/handlers.c
View
@@ -71,6 +71,7 @@ void pthreads_write_property(PTHREADS_WRITE_PROPERTY_PASSTHRU_D) {
case IS_OBJECT:
case IS_NULL:
case IS_DOUBLE:
+ case IS_RESOURCE:
case IS_BOOL: {
if (pthreads_store_write(pthreads->store, Z_STRVAL_P(member), Z_STRLEN_P(member), &value TSRMLS_CC)!=SUCCESS){
zend_error_noreturn(
3  src/object.c
View
@@ -348,6 +348,7 @@ static int pthreads_connect(PTHREAD source, PTHREAD destination TSRMLS_DC) {
destination->thread = source->thread;
destination->tid = source->tid;
destination->tls = source->tls;
+ destination->cls = source->cls;
destination->cid = source->cid;
destination->address = source->address;
@@ -400,6 +401,7 @@ static void pthreads_base_ctor(PTHREAD base, zend_class_entry *entry TSRMLS_DC)
zend_llist_init(&base->stack->objects, sizeof(void**), NULL, 1);
}
}
+ base->resources = pthreads_resources_alloc(TSRMLS_C);
}
} /* }}} */
@@ -435,6 +437,7 @@ static void pthreads_base_dtor(void *arg TSRMLS_DC) {
free(base->address);
}
}
+ pthreads_resources_free(base->resources TSRMLS_CC);
#if PHP_VERSION_ID > 50399
{
27 src/prepare.c
View
@@ -26,6 +26,10 @@
# include <src/object.h>
#endif
+#ifndef HAVE_PTHREADS_RESOURCES_H
+# include <src/resources.h>
+#endif
+
/* {{{ prepared property info ctor */
static void pthreads_preparation_property_info_ctor(zend_property_info *pi); /* }}} */
/* {{{ prepared property info dtor */
@@ -48,6 +52,9 @@ static zend_trait_method_reference * pthreads_preparation_copy_trait_method_ref
/* {{{ fix the scope of methods such that self:: and parent:: work everywhere */
static void pthreads_apply_method_scope(zend_function *function, zend_class_entry *scope TSRMLS_DC); /* }}} */
+/* {{{ prepared resource destructor */
+static void pthreads_prepared_resource_dtor(zend_rsrc_list_entry *entry); /* }}} */
+
/* {{{ fetch prepared class entry */
zend_class_entry* pthreads_prepared_entry(PTHREAD thread, zend_class_entry *candidate TSRMLS_DC) {
zend_class_entry *prepared = NULL, **searched = NULL;
@@ -372,6 +379,12 @@ void pthreads_prepare(PTHREAD thread TSRMLS_DC){
NULL, &included, sizeof(int), 0
);
}
+
+ /* set sensible resource destructor */
+ if (EG(regular_list).pDestructor) {
+ thread->resources->destructor = EG(regular_list).pDestructor;
+ }
+ EG(regular_list).pDestructor = pthreads_prepared_resource_dtor;
} /* }}} */
/* {{{ copy property info
@@ -460,4 +473,18 @@ static void pthreads_apply_method_scope(zend_function *function, zend_class_entr
}
} /* }}} */
+/* {{{ destroy a resource, if we created it */
+static void pthreads_prepared_resource_dtor(zend_rsrc_list_entry *entry) {
+ TSRMLS_FETCH();
+
+ PTHREAD object = PTHREADS_FETCH_FROM(EG(This));
+ if (object) {
+ if (!pthreads_resources_kept(object->resources, entry TSRMLS_CC)) {
+ if (object->resources->destructor) {
+ object->resources->destructor(entry);
+ }
+ }
+ }
+} /* }}} */
+
#endif
52 src/store.c
View
@@ -30,6 +30,10 @@
# include <src/object.h>
#endif
+#ifndef HAVE_PTHREADS_RESOURCES_H
+# include <src/resources.h>
+#endif
+
typedef struct _pthreads_storage {
void *data;
size_t length;
@@ -325,6 +329,12 @@ static pthreads_storage pthreads_store_create(zval *unstore TSRMLS_DC){
case IS_LONG: {
storage->exists = ((storage->lval=Z_LVAL_P(unstore)) > 0L);
} break;
+
+ case IS_RESOURCE: {
+ storage->data = tsrm_ls;
+ storage->lval = Z_RESVAL_P(unstore);
+ storage->exists = 1;
+ } break;
case IS_DOUBLE: storage->exists = ((storage->dval=Z_DVAL_P(unstore)) > 0.0); break;
@@ -363,7 +373,47 @@ static int pthreads_store_convert(pthreads_storage storage, zval *pzval TSRMLS_D
case IS_BOOL: ZVAL_BOOL(pzval, storage->lval); break;
case IS_LONG: ZVAL_LONG(pzval, storage->lval); break;
case IS_DOUBLE: ZVAL_DOUBLE(pzval, storage->dval); break;
-
+ case IS_RESOURCE: {
+ if (storage->data != tsrm_ls) {
+ zend_rsrc_list_entry *original;
+ PTHREAD object = PTHREADS_FETCH_FROM(EG(This));
+ if (zend_hash_index_find(&PTHREADS_EG(object->cls, regular_list), storage->lval, (void**)&original)==SUCCESS) {
+ zend_rsrc_list_entry *search;
+ HashPosition position;
+ zend_bool found = 0;
+ int existed = 0;
+ for(zend_hash_internal_pointer_reset_ex(&EG(regular_list), &position);
+ zend_hash_get_current_data_ex(&EG(regular_list), (void**) &search, &position)==SUCCESS;
+ zend_hash_move_forward_ex(&EG(regular_list), &position)) {
+ if (search->ptr == original->ptr) {
+ found=1;
+ break;
+ }
+ existed++;
+ }
+ if (!found) {
+ int created;
+ zend_rsrc_list_entry create;
+ zend_rsrc_list_entry *keep;
+ {
+ create.type = original->type;
+ create.ptr = original->ptr;
+ create.refcount = ++create.refcount;
+ created=zend_hash_next_free_element(&EG(regular_list));
+
+ if (zend_hash_index_update(
+ &EG(regular_list), created, (void*) &create, sizeof(zend_rsrc_list_entry), (void**) &keep
+ )==SUCCESS) {
+ ZVAL_RESOURCE(pzval, created);
+ pthreads_resources_keep(
+ object->resources, keep TSRMLS_CC
+ );
+ } else ZVAL_NULL(pzval);
+ }
+ } else ZVAL_RESOURCE(pzval, existed);
+ } else ZVAL_RESOURCE(pzval, storage->lval);
+ } else ZVAL_RESOURCE(pzval, storage->lval);
+ } break;
case IS_ARRAY:
case IS_OBJECT: {
result = pthreads_store_tozval(
9 src/thread.h
View
@@ -38,6 +38,10 @@
# include <src/store.h>
#endif
+#ifndef HAVE_PTHREADS_RESOURCES_H
+# include <src/resources.h>
+#endif
+
/* {{{ stack structure */
typedef struct _pthreads_stack {
zend_llist objects;
@@ -112,6 +116,11 @@ typedef struct _pthread_construct {
* Thread Address
*/
pthreads_address address;
+
+ /**
+ * Shared Resources
+ **/
+ pthreads_resources resources;
} *PTHREAD;
/* {{{ comparison function */
Please sign in to comment.
Something went wrong with that request. Please try again.