Skip to content

Commit 3505793

Browse files
committed
optimize
1 parent cb151a7 commit 3505793

11 files changed

Lines changed: 146 additions & 83 deletions

cgi.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ func addPreparedEnvToServer(fc *frankenPHPContext, trackVarsArray *C.zval) {
212212
//export go_register_variables
213213
func go_register_variables(threadIndex C.uintptr_t, trackVarsArray *C.zval) {
214214
thread := phpThreads[threadIndex]
215-
fc := thread.context().Value(contextKey).(*frankenPHPContext)
215+
fc := thread.frankenPHPContext()
216216

217217
if fc.request != nil {
218218
addKnownVariablesToServer(thread, fc, trackVarsArray)
@@ -279,7 +279,7 @@ func splitPos(path string, splitPath []string) int {
279279
//export go_update_request_info
280280
func go_update_request_info(threadIndex C.uintptr_t, info *C.sapi_request_info) C.bool {
281281
thread := phpThreads[threadIndex]
282-
fc := thread.context().Value(contextKey).(*frankenPHPContext)
282+
fc := thread.frankenPHPContext()
283283
request := fc.request
284284

285285
if request == nil {

context.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ type frankenPHPContext struct {
3838
startedAt time.Time
3939
}
4040

41+
type contextHolder struct {
42+
ctx context.Context
43+
frankenPHPContext *frankenPHPContext
44+
}
45+
4146
// fromContext extracts the frankenPHPContext from a context.
4247
func fromContext(ctx context.Context) (fctx *frankenPHPContext, ok bool) {
4348
fctx, ok = ctx.Value(contextKey).(*frankenPHPContext)

frankenphp.go

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ func Init(options ...Option) error {
274274
return err
275275
}
276276

277-
regularRequestChan = make(chan context.Context, opt.numThreads-workerThreadCount)
277+
regularRequestChan = make(chan contextHolder, opt.numThreads-workerThreadCount)
278278
regularThreads = make([]*phpThread, 0, opt.numThreads-workerThreadCount)
279279
for i := 0; i < opt.numThreads-workerThreadCount; i++ {
280280
convertToRegularThread(getInactivePHPThread())
@@ -346,6 +346,8 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error
346346
ctx := request.Context()
347347
fc, ok := fromContext(ctx)
348348

349+
ch := contextHolder{ctx, fc}
350+
349351
if !ok {
350352
return ErrInvalidRequest
351353
}
@@ -358,17 +360,17 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error
358360

359361
// Detect if a worker is available to handle this request
360362
if fc.worker != nil {
361-
return fc.worker.handleRequest(ctx)
363+
return fc.worker.handleRequest(ch)
362364
}
363365

364366
// If no worker was available, send the request to non-worker threads
365-
return handleRequestWithRegularPHPThreads(ctx)
367+
return handleRequestWithRegularPHPThreads(ch)
366368
}
367369

368370
//export go_ub_write
369371
func go_ub_write(threadIndex C.uintptr_t, cBuf *C.char, length C.int) (C.size_t, C.bool) {
370-
ctx := phpThreads[threadIndex].context()
371-
fc := ctx.Value(contextKey).(*frankenPHPContext)
372+
thread := phpThreads[threadIndex]
373+
fc := thread.frankenPHPContext()
372374

373375
if fc.isDone {
374376
return 0, C.bool(true)
@@ -383,14 +385,27 @@ func go_ub_write(threadIndex C.uintptr_t, cBuf *C.char, length C.int) (C.size_t,
383385
writer = fc.responseWriter
384386
}
385387

388+
var ctx context.Context
389+
386390
i, e := writer.Write(unsafe.Slice((*byte)(unsafe.Pointer(cBuf)), length))
387-
if e != nil && fc.logger.Enabled(ctx, slog.LevelWarn) {
388-
fc.logger.LogAttrs(ctx, slog.LevelWarn, "write error", slog.Any("error", e))
391+
if e != nil {
392+
ctx = thread.context()
393+
394+
if fc.logger.Enabled(ctx, slog.LevelWarn) {
395+
fc.logger.LogAttrs(ctx, slog.LevelWarn, "write error", slog.Any("error", e))
396+
}
389397
}
390398

391-
if fc.responseWriter == nil && fc.logger.Enabled(ctx, slog.LevelInfo) {
399+
if fc.responseWriter == nil {
392400
// probably starting a worker script, log the output
393-
fc.logger.LogAttrs(ctx, slog.LevelInfo, writer.(*bytes.Buffer).String())
401+
402+
if ctx == nil {
403+
ctx = thread.context()
404+
}
405+
406+
if fc.logger.Enabled(ctx, slog.LevelInfo) {
407+
fc.logger.LogAttrs(ctx, slog.LevelInfo, writer.(*bytes.Buffer).String())
408+
}
394409
}
395410

396411
return C.size_t(i), C.bool(fc.clientHasClosed())
@@ -400,7 +415,7 @@ func go_ub_write(threadIndex C.uintptr_t, cBuf *C.char, length C.int) (C.size_t,
400415
func go_apache_request_headers(threadIndex C.uintptr_t) (*C.go_string, C.size_t) {
401416
thread := phpThreads[threadIndex]
402417
ctx := thread.context()
403-
fc := ctx.Value(contextKey).(*frankenPHPContext)
418+
fc := thread.frankenPHPContext()
404419

405420
if fc.responseWriter == nil {
406421
// worker mode, not handling a request
@@ -477,13 +492,12 @@ func splitRawHeader(rawHeader *C.char, length int) (string, string) {
477492

478493
//export go_write_headers
479494
func go_write_headers(threadIndex C.uintptr_t, status C.int, headers *C.zend_llist) C.bool {
480-
ctx := phpThreads[threadIndex].context()
481-
if ctx == nil {
495+
thread := phpThreads[threadIndex]
496+
fc := thread.frankenPHPContext()
497+
if fc == nil {
482498
return C.bool(false)
483499
}
484500

485-
fc := ctx.Value(contextKey).(*frankenPHPContext)
486-
487501
if fc.isDone {
488502
return C.bool(false)
489503
}
@@ -506,6 +520,8 @@ func go_write_headers(threadIndex C.uintptr_t, status C.int, headers *C.zend_lli
506520
// go panics on invalid status code
507521
// https://github.com/golang/go/blob/9b8742f2e79438b9442afa4c0a0139d3937ea33f/src/net/http/server.go#L1162
508522
if goStatus < 100 || goStatus > 999 {
523+
ctx := thread.context()
524+
509525
if logger.Enabled(ctx, slog.LevelWarn) {
510526
logger.LogAttrs(ctx, slog.LevelWarn, "Invalid response status code", slog.Int("status_code", goStatus))
511527
}
@@ -528,13 +544,12 @@ func go_write_headers(threadIndex C.uintptr_t, status C.int, headers *C.zend_lli
528544

529545
//export go_sapi_flush
530546
func go_sapi_flush(threadIndex C.uintptr_t) bool {
531-
ctx := phpThreads[threadIndex].context()
532-
if ctx == nil {
547+
thread := phpThreads[threadIndex]
548+
fc := thread.frankenPHPContext()
549+
if fc == nil {
533550
return false
534551
}
535552

536-
fc := ctx.Value(contextKey).(*frankenPHPContext)
537-
538553
if fc.responseWriter == nil {
539554
return false
540555
}
@@ -543,16 +558,20 @@ func go_sapi_flush(threadIndex C.uintptr_t) bool {
543558
return true
544559
}
545560

546-
if err := http.NewResponseController(fc.responseWriter).Flush(); err != nil && logger.Enabled(ctx, slog.LevelWarn) {
547-
logger.LogAttrs(ctx, slog.LevelWarn, "the current responseWriter is not a flusher, if you are not using a custom build, please report this issue", slog.Any("error", err))
561+
if err := http.NewResponseController(fc.responseWriter).Flush(); err != nil {
562+
ctx := thread.context()
563+
564+
if logger.Enabled(ctx, slog.LevelWarn) {
565+
logger.LogAttrs(ctx, slog.LevelWarn, "the current responseWriter is not a flusher, if you are not using a custom build, please report this issue", slog.Any("error", err))
566+
}
548567
}
549568

550569
return false
551570
}
552571

553572
//export go_read_post
554573
func go_read_post(threadIndex C.uintptr_t, cBuf *C.char, countBytes C.size_t) (readBytes C.size_t) {
555-
fc := phpThreads[threadIndex].context().Value(contextKey).(*frankenPHPContext)
574+
fc := phpThreads[threadIndex].frankenPHPContext()
556575

557576
if fc.responseWriter == nil {
558577
return 0
@@ -571,7 +590,7 @@ func go_read_post(threadIndex C.uintptr_t, cBuf *C.char, countBytes C.size_t) (r
571590

572591
//export go_read_cookies
573592
func go_read_cookies(threadIndex C.uintptr_t) *C.char {
574-
request := phpThreads[threadIndex].context().Value(contextKey).(*frankenPHPContext).request
593+
request := phpThreads[threadIndex].frankenPHPContext().request
575594
if request == nil {
576595
return nil
577596
}
@@ -615,7 +634,7 @@ func go_log(message *C.char, level C.int) {
615634

616635
//export go_is_context_done
617636
func go_is_context_done(threadIndex C.uintptr_t) C.bool {
618-
return C.bool(phpThreads[threadIndex].context().Value(contextKey).(*frankenPHPContext).isDone)
637+
return C.bool(phpThreads[threadIndex].frankenPHPContext().isDone)
619638
}
620639

621640
// ExecuteScriptCLI executes the PHP script passed as parameter.

frankenphp_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"bytes"
99
"context"
1010
"errors"
11+
"flag"
1112
"fmt"
1213
"io"
1314
"log"
@@ -136,6 +137,16 @@ func testPost(url string, body string, handler func(http.ResponseWriter, *http.R
136137
return testRequest(req, handler, t)
137138
}
138139

140+
func TestMain(m *testing.M) {
141+
flag.Parse()
142+
143+
if !testing.Verbose() {
144+
slog.SetDefault(slog.New(slog.DiscardHandler))
145+
}
146+
147+
os.Exit(m.Run())
148+
}
149+
139150
func TestHelloWorld_module(t *testing.T) { testHelloWorld(t, nil) }
140151
func TestHelloWorld_worker(t *testing.T) {
141152
testHelloWorld(t, &testOptions{workerScript: "index.php"})

phpthread.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
type phpThread struct {
1717
runtime.Pinner
1818
threadIndex int
19-
requestChan chan context.Context
19+
requestChan chan contextHolder
2020
drainChan chan struct{}
2121
handlerMu sync.Mutex
2222
handler threadHandler
@@ -30,12 +30,13 @@ type threadHandler interface {
3030
beforeScriptExecution() string
3131
afterScriptExecution(exitStatus int)
3232
context() context.Context
33+
frankenPHPContext() *frankenPHPContext
3334
}
3435

3536
func newPHPThread(threadIndex int) *phpThread {
3637
return &phpThread{
3738
threadIndex: threadIndex,
38-
requestChan: make(chan context.Context),
39+
requestChan: make(chan contextHolder),
3940
state: newThreadState(),
4041
}
4142
}
@@ -104,6 +105,10 @@ func (thread *phpThread) transitionToNewHandler() string {
104105
return thread.handler.beforeScriptExecution()
105106
}
106107

108+
func (thread *phpThread) frankenPHPContext() *frankenPHPContext {
109+
return thread.handler.frankenPHPContext()
110+
}
111+
107112
func (thread *phpThread) context() context.Context {
108113
return thread.handler.context()
109114
}

threadinactive.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ func (handler *inactiveThread) afterScriptExecution(int) {
3939
panic("inactive threads should not execute scripts")
4040
}
4141

42+
func (handler *inactiveThread) frankenPHPContext() *frankenPHPContext {
43+
return nil
44+
}
45+
4246
func (handler *inactiveThread) context() context.Context {
4347
return nil
4448
}

threadregular.go

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@ import (
99
// executes PHP scripts in a web context
1010
// implements the threadHandler interface
1111
type regularThread struct {
12+
contextHolder
13+
1214
state *threadState
1315
thread *phpThread
14-
ctx context.Context
1516
}
1617

1718
var (
1819
regularThreads []*phpThread
1920
regularThreadMu = &sync.RWMutex{}
20-
regularRequestChan chan context.Context
21+
regularRequestChan chan contextHolder
2122
)
2223

2324
func convertToRegularThread(thread *phpThread) {
@@ -47,10 +48,14 @@ func (handler *regularThread) beforeScriptExecution() string {
4748
panic("unexpected state: " + handler.state.name())
4849
}
4950

50-
func (handler *regularThread) afterScriptExecution(int) {
51+
func (handler *regularThread) afterScriptExecution(_ int) {
5152
handler.afterRequest()
5253
}
5354

55+
func (handler *regularThread) frankenPHPContext() *frankenPHPContext {
56+
return handler.contextHolder.frankenPHPContext
57+
}
58+
5459
func (handler *regularThread) context() context.Context {
5560
return handler.ctx
5661
}
@@ -65,37 +70,35 @@ func (handler *regularThread) waitForRequest() string {
6570

6671
handler.state.markAsWaiting(true)
6772

68-
var ctx context.Context
73+
var ch contextHolder
6974
select {
7075
case <-handler.thread.drainChan:
7176
// go back to beforeScriptExecution
7277
return handler.beforeScriptExecution()
73-
case ctx = <-regularRequestChan:
78+
case ch = <-regularRequestChan:
7479
}
7580

76-
handler.ctx = ctx
81+
handler.ctx = ch.ctx
82+
handler.contextHolder.frankenPHPContext = ch.frankenPHPContext
7783
handler.state.markAsWaiting(false)
7884

7985
// set the scriptFilename that should be executed
80-
return ctx.Value(contextKey).(*frankenPHPContext).scriptFilename
86+
return handler.contextHolder.frankenPHPContext.scriptFilename
8187
}
8288

8389
func (handler *regularThread) afterRequest() {
84-
fc := handler.ctx.Value(contextKey).(*frankenPHPContext)
85-
86-
fc.closeContext()
90+
handler.contextHolder.frankenPHPContext.closeContext()
91+
handler.contextHolder.frankenPHPContext = nil
8792
handler.ctx = nil
8893
}
8994

90-
func handleRequestWithRegularPHPThreads(ctx context.Context) error {
95+
func handleRequestWithRegularPHPThreads(ch contextHolder) error {
9196
metrics.StartRequest()
9297

93-
fc := ctx.Value(contextKey).(*frankenPHPContext)
94-
9598
select {
96-
case regularRequestChan <- ctx:
99+
case regularRequestChan <- ch:
97100
// a thread was available to handle the request immediately
98-
<-fc.done
101+
<-ch.frankenPHPContext.done
99102
metrics.StopRequest()
100103

101104
return nil
@@ -107,19 +110,19 @@ func handleRequestWithRegularPHPThreads(ctx context.Context) error {
107110
metrics.QueuedRequest()
108111
for {
109112
select {
110-
case regularRequestChan <- ctx:
113+
case regularRequestChan <- ch:
111114
metrics.DequeuedRequest()
112-
<-fc.done
115+
<-ch.frankenPHPContext.done
113116
metrics.StopRequest()
114117

115118
return nil
116-
case scaleChan <- fc:
119+
case scaleChan <- ch.frankenPHPContext:
117120
// the request has triggered scaling, continue to wait for a thread
118121
case <-timeoutChan(maxWaitTime):
119122
// the request has timed out stalling
120123
metrics.DequeuedRequest()
121124

122-
fc.reject(ErrMaxWaitTimeExceeded)
125+
ch.frankenPHPContext.reject(ErrMaxWaitTimeExceeded)
123126

124127
return ErrMaxWaitTimeExceeded
125128
}

threadtasks_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ func (handler *taskThread) afterScriptExecution(_ int) {
6565
panic("task threads should not execute scripts")
6666
}
6767

68+
func (handler *taskThread) frankenPHPContext() *frankenPHPContext {
69+
return nil
70+
}
71+
6872
func (handler *taskThread) context() context.Context {
6973
return nil
7074
}

0 commit comments

Comments
 (0)