1
+ #define bytes_sent bytes
1
2
/*
2
3
+----------------------------------------------------------------------+
3
4
| PHP version 4.0 |
@@ -34,14 +35,24 @@ typedef struct {
34
35
void (* on_close )(int );
35
36
} php_thttpd_globals ;
36
37
37
- static php_thttpd_globals thttpd_globals ;
38
38
39
+ #ifdef ZTS
40
+ static int thttpd_globals_id ;
41
+ #define TLS_D php_thttpd_globals *thttpd_context
42
+ #define TLS_DC , TLS_D
43
+ #define TLS_C thttpd_context
44
+ #define TLS_CC , thttpd_context
45
+ #define TG (v ) (thttpd_context->v)
46
+ #define TLS_FETCH () TLS_D = ts_resource(thttpd_globals_id)
47
+ #else
48
+ static php_thttpd_globals thttpd_globals ;
39
49
#define TLS_D
40
50
#define TLS_DC
41
51
#define TLS_C
42
52
#define TLS_CC
43
53
#define TG (v ) (thttpd_globals.v)
44
54
#define TLS_FETCH ()
55
+ #endif
45
56
46
57
static int sapi_thttpd_ub_write (const char * str , uint str_length )
47
58
{
@@ -78,6 +89,7 @@ static int sapi_thttpd_send_headers(sapi_headers_struct *sapi_headers SLS_DC)
78
89
zend_llist_position pos ;
79
90
sapi_header_struct * h ;
80
91
size_t len ;
92
+ TLS_FETCH ();
81
93
82
94
if (!SG (sapi_headers ).http_status_line ) {
83
95
snprintf (buf , 1023 , "HTTP/1.0 %d Something\r\n" , SG (sapi_headers ).http_response_code );
@@ -194,7 +206,7 @@ static void sapi_thttpd_register_variables(zval *track_vars_array ELS_DC SLS_DC
194
206
195
207
#define CONDADD (name , field ) \
196
208
if (TG(hc)->field[0]) { \
197
- php_register_variable(#name, TG(hc)->field, track_vars_array ELS_CC PLS_C ); \
209
+ php_register_variable(#name, TG(hc)->field, track_vars_array ELS_CC PLS_CC ); \
198
210
}
199
211
200
212
CONDADD (HTTP_REFERER , referer );
@@ -212,7 +224,7 @@ static void sapi_thttpd_register_variables(zval *track_vars_array ELS_DC SLS_DC
212
224
}
213
225
214
226
if (TG (hc )-> authorization [0 ])
215
- php_register_variable ("AUTH_TYPE" , "Basic" , track_vars_array ELS_CC PLS_C );
227
+ php_register_variable ("AUTH_TYPE" , "Basic" , track_vars_array ELS_CC PLS_CC );
216
228
}
217
229
218
230
static sapi_module_struct thttpd_sapi_module = {
@@ -313,11 +325,187 @@ static void thttpd_request_dtor(TLS_D SLS_DC)
313
325
free (SG (request_info ).path_translated );
314
326
}
315
327
316
- off_t thttpd_php_request (httpd_conn * hc )
328
+ #ifdef ZTS
329
+
330
+ #ifdef TSRM_ST
331
+ #define thread_create_simple_detached (n ) st_thread_create(n, NULL, 0, 0)
332
+ #define thread_usleep (n ) st_usleep(n)
333
+ #define thread_exit () st_thread_exit(NULL)
334
+ /* No preemption, simple operations are safe */
335
+ #define thread_atomic_inc (n ) (++n)
336
+ #define thread_atomic_dec (n ) (--n)
337
+ #else
338
+ #error No thread primitives available
339
+ #endif
340
+
341
+ /* We might want to replace this with a STAILQ */
342
+ typedef struct qreq {
343
+ httpd_conn * hc ;
344
+ struct qreq * next ;
345
+ } qreq_t ;
346
+
347
+ static MUTEX_T qr_lock ;
348
+ static qreq_t * queued_requests ;
349
+ static qreq_t * last_qr ;
350
+ static int nr_free_threads ;
351
+ static int nr_threads ;
352
+ static int max_threads = 50 ;
353
+
354
+ #define HANDLE_STRINGS () { \
355
+ HANDLE_STR(encodedurl); \
356
+ HANDLE_STR(decodedurl); \
357
+ HANDLE_STR(origfilename); \
358
+ HANDLE_STR(expnfilename); \
359
+ HANDLE_STR(pathinfo); \
360
+ HANDLE_STR(query); \
361
+ HANDLE_STR(referer); \
362
+ HANDLE_STR(useragent); \
363
+ HANDLE_STR(accept); \
364
+ HANDLE_STR(accepte); \
365
+ HANDLE_STR(acceptl); \
366
+ HANDLE_STR(cookie); \
367
+ HANDLE_STR(contenttype); \
368
+ HANDLE_STR(authorization); \
369
+ HANDLE_STR(remoteuser); \
370
+ }
371
+
372
+ static httpd_conn * duplicate_conn (httpd_conn * hc , httpd_conn * nhc )
373
+ {
374
+ memcpy (nhc , hc , sizeof (* nhc ));
375
+
376
+ #define HANDLE_STR (m ) nhc->m = nhc->m ? strdup(nhc->m) : NULL
377
+ HANDLE_STRINGS ();
378
+ #undef HANDLE_STR
379
+
380
+ return nhc ;
381
+ }
382
+
383
+ static void destroy_conn (httpd_conn * hc )
384
+ {
385
+ #define HANDLE_STR (m ) if (hc->m) free(hc->m)
386
+ HANDLE_STRINGS ();
387
+ #undef HANDLE_STR
388
+ }
389
+
390
+ static httpd_conn * dequeue_request (void )
391
+ {
392
+ httpd_conn * ret = NULL ;
393
+ qreq_t * m ;
394
+
395
+ tsrm_mutex_lock (qr_lock );
396
+ if (queued_requests ) {
397
+ m = queued_requests ;
398
+ ret = m -> hc ;
399
+ if (!(queued_requests = m -> next ))
400
+ last_qr = NULL ;
401
+ free (m );
402
+ }
403
+ tsrm_mutex_unlock (qr_lock );
404
+
405
+ return ret ;
406
+ }
407
+
408
+ static void * worker_thread (void * );
409
+
410
+ static void queue_request (httpd_conn * hc )
411
+ {
412
+ qreq_t * m ;
413
+ httpd_conn * nhc ;
414
+
415
+ /* Mark as long-running request */
416
+ hc -> file_address = (char * ) 1 ;
417
+
418
+ /*
419
+ * We cannot synchronously revoke accesses to hc in the worker
420
+ * thread, so we need to pass a copy of hc to the worker thread.
421
+ */
422
+ nhc = malloc (sizeof * nhc );
423
+ duplicate_conn (hc , nhc );
424
+
425
+ /* Allocate request queue container */
426
+ m = malloc (sizeof * m );
427
+ m -> hc = nhc ;
428
+ m -> next = NULL ;
429
+
430
+ tsrm_mutex_lock (qr_lock );
431
+ /* Create new threads when reaching a certain threshhold */
432
+ if (nr_threads < max_threads && nr_free_threads < 2 ) {
433
+ nr_threads ++ ; /* protected by qr_lock */
434
+
435
+ thread_atomic_inc (nr_free_threads );
436
+ thread_create_simple_detached (worker_thread );
437
+ }
438
+ /* Insert container into request queue */
439
+ if (queued_requests )
440
+ last_qr -> next = m ;
441
+ else
442
+ queued_requests = m ;
443
+ last_qr = m ;
444
+ tsrm_mutex_unlock (qr_lock );
445
+ }
446
+
447
+ static off_t thttpd_real_php_request (httpd_conn * hc TLS_DC SLS_DC );
448
+
449
+ static void * worker_thread (void * dummy )
317
450
{
451
+ int do_work = 50 ;
452
+ httpd_conn * hc ;
318
453
SLS_FETCH ();
319
454
TLS_FETCH ();
320
455
456
+ while (do_work ) {
457
+ hc = dequeue_request ();
458
+
459
+ if (!hc ) {
460
+ /* do_work--; */
461
+ thread_usleep (500000 );
462
+ continue ;
463
+ }
464
+ /* do_work = 50; */
465
+
466
+ thread_atomic_dec (nr_free_threads );
467
+
468
+ thttpd_real_php_request (hc TLS_CC SLS_CC );
469
+ shutdown (hc -> conn_fd , 0 );
470
+ destroy_conn (hc );
471
+ free (hc );
472
+
473
+ thread_atomic_inc (nr_free_threads );
474
+ }
475
+ thread_atomic_dec (nr_free_threads );
476
+ thread_atomic_dec (nr_threads );
477
+ thread_exit ();
478
+ }
479
+
480
+ static void remove_dead_conn (int fd )
481
+ {
482
+ qreq_t * m , * prev = NULL ;
483
+
484
+ tsrm_mutex_lock (qr_lock );
485
+ m = queued_requests ;
486
+ while (m ) {
487
+ if (m -> hc -> conn_fd == fd ) {
488
+ if (prev )
489
+ if (!(prev -> next = m -> next ))
490
+ last_qr = prev ;
491
+ else
492
+ if (!(queued_requests = m -> next ))
493
+ last_qr = NULL ;
494
+ destroy_conn (m -> hc );
495
+ free (m -> hc );
496
+ free (m );
497
+ break ;
498
+ }
499
+ prev = m ;
500
+ m = m -> next ;
501
+ }
502
+ tsrm_mutex_unlock (qr_lock );
503
+ }
504
+
505
+ #endif
506
+
507
+ static off_t thttpd_real_php_request (httpd_conn * hc TLS_DC SLS_DC )
508
+ {
321
509
TG (hc ) = hc ;
322
510
hc -> bytes_sent = 0 ;
323
511
@@ -330,37 +518,67 @@ off_t thttpd_php_request(httpd_conn *hc)
330
518
return 0 ;
331
519
}
332
520
521
+ off_t thttpd_php_request (httpd_conn * hc )
522
+ {
523
+ #ifdef ZTS
524
+ queue_request (hc );
525
+ #else
526
+ SLS_FETCH ();
527
+ TLS_FETCH ();
528
+ return thttpd_real_php_request (hc TLS_CC SLS_CC );
529
+ #endif
530
+ }
531
+
333
532
void thttpd_register_on_close (void (* arg )(int ))
334
533
{
534
+ TLS_FETCH ();
335
535
TG (on_close ) = arg ;
336
536
}
337
537
338
538
void thttpd_closed_conn (int fd )
339
539
{
540
+ TLS_FETCH ();
340
541
if (TG (on_close )) TG (on_close )(fd );
341
542
}
342
543
343
544
int thttpd_get_fd (void )
344
545
{
546
+ TLS_FETCH ();
345
547
return TG (hc )-> conn_fd ;
346
548
}
347
549
348
550
void thttpd_set_dont_close (void )
349
551
{
552
+ TLS_FETCH ();
350
553
TG (hc )-> file_address = (char * ) 1 ;
351
554
}
352
555
556
+
353
557
void thttpd_php_init (void )
354
558
{
559
+ #ifdef ZTS
560
+ tsrm_startup (1 , 1 , 0 , NULL );
561
+ thttpd_globals_id = ts_allocate_id (sizeof (php_thttpd_globals ), NULL , NULL );
562
+ qr_lock = tsrm_mutex_alloc ();
563
+ thttpd_register_on_close (remove_dead_conn );
564
+ #endif
355
565
sapi_startup (& thttpd_sapi_module );
356
566
thttpd_sapi_module .startup (& thttpd_sapi_module );
357
- SG (server_context ) = (void * ) 1 ;
567
+ {
568
+ SLS_FETCH ();
569
+ SG (server_context ) = (void * ) 1 ;
570
+ }
358
571
}
359
572
360
573
void thttpd_php_shutdown (void )
361
574
{
575
+ SLS_FETCH ();
576
+
362
577
if (SG (server_context ) != NULL ) {
363
578
thttpd_sapi_module .shutdown (& thttpd_sapi_module );
364
579
sapi_shutdown ();
580
+ #ifdef ZTS
581
+ tsrm_shutdown ();
582
+ #endif
365
583
}
366
584
}
0 commit comments