Skip to content

Commit cb151a7

Browse files
committed
refactor: rely on context.Context for log/slog and others
1 parent 724c0b1 commit cb151a7

11 files changed

Lines changed: 126 additions & 85 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.getRequestContext()
215+
fc := thread.context().Value(contextKey).(*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.getRequestContext()
282+
fc := thread.context().Value(contextKey).(*frankenPHPContext)
283283
request := fc.request
284284

285285
if request == nil {

frankenphp.go

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,8 @@ func Init(options ...Option) error {
233233

234234
if opt.logger == nil {
235235
// set a default logger
236-
// to disable logging, set the logger to slog.New(slog.NewTextHandler(io.Discard, nil))
237-
opt.logger = slog.New(slog.NewTextHandler(os.Stdout, nil))
236+
// to disable logging, set the logger to slog.New(slog.DiscardHandler)
237+
opt.logger = slog.Default()
238238
}
239239

240240
loggerMu.Lock()
@@ -274,7 +274,7 @@ func Init(options ...Option) error {
274274
return err
275275
}
276276

277-
regularRequestChan = make(chan *frankenPHPContext, opt.numThreads-workerThreadCount)
277+
regularRequestChan = make(chan context.Context, opt.numThreads-workerThreadCount)
278278
regularThreads = make([]*phpThread, 0, opt.numThreads-workerThreadCount)
279279
for i := 0; i < opt.numThreads-workerThreadCount; i++ {
280280
convertToRegularThread(getInactivePHPThread())
@@ -343,7 +343,9 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error
343343
return ErrNotRunning
344344
}
345345

346-
fc, ok := fromContext(request.Context())
346+
ctx := request.Context()
347+
fc, ok := fromContext(ctx)
348+
347349
if !ok {
348350
return ErrInvalidRequest
349351
}
@@ -356,16 +358,17 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error
356358

357359
// Detect if a worker is available to handle this request
358360
if fc.worker != nil {
359-
return fc.worker.handleRequest(fc)
361+
return fc.worker.handleRequest(ctx)
360362
}
361363

362364
// If no worker was available, send the request to non-worker threads
363-
return handleRequestWithRegularPHPThreads(fc)
365+
return handleRequestWithRegularPHPThreads(ctx)
364366
}
365367

366368
//export go_ub_write
367369
func go_ub_write(threadIndex C.uintptr_t, cBuf *C.char, length C.int) (C.size_t, C.bool) {
368-
fc := phpThreads[threadIndex].getRequestContext()
370+
ctx := phpThreads[threadIndex].context()
371+
fc := ctx.Value(contextKey).(*frankenPHPContext)
369372

370373
if fc.isDone {
371374
return 0, C.bool(true)
@@ -381,13 +384,13 @@ func go_ub_write(threadIndex C.uintptr_t, cBuf *C.char, length C.int) (C.size_t,
381384
}
382385

383386
i, e := writer.Write(unsafe.Slice((*byte)(unsafe.Pointer(cBuf)), length))
384-
if e != nil {
385-
fc.logger.LogAttrs(context.Background(), slog.LevelWarn, "write error", slog.Any("error", e))
387+
if e != nil && fc.logger.Enabled(ctx, slog.LevelWarn) {
388+
fc.logger.LogAttrs(ctx, slog.LevelWarn, "write error", slog.Any("error", e))
386389
}
387390

388-
if fc.responseWriter == nil {
391+
if fc.responseWriter == nil && fc.logger.Enabled(ctx, slog.LevelInfo) {
389392
// probably starting a worker script, log the output
390-
fc.logger.Info(writer.(*bytes.Buffer).String())
393+
fc.logger.LogAttrs(ctx, slog.LevelInfo, writer.(*bytes.Buffer).String())
391394
}
392395

393396
return C.size_t(i), C.bool(fc.clientHasClosed())
@@ -396,12 +399,15 @@ func go_ub_write(threadIndex C.uintptr_t, cBuf *C.char, length C.int) (C.size_t,
396399
//export go_apache_request_headers
397400
func go_apache_request_headers(threadIndex C.uintptr_t) (*C.go_string, C.size_t) {
398401
thread := phpThreads[threadIndex]
399-
fc := thread.getRequestContext()
402+
ctx := thread.context()
403+
fc := ctx.Value(contextKey).(*frankenPHPContext)
400404

401405
if fc.responseWriter == nil {
402406
// worker mode, not handling a request
403407

404-
logger.LogAttrs(context.Background(), slog.LevelDebug, "apache_request_headers() called in non-HTTP context", slog.String("worker", fc.worker.name))
408+
if logger.Enabled(ctx, slog.LevelDebug) {
409+
logger.LogAttrs(ctx, slog.LevelDebug, "apache_request_headers() called in non-HTTP context", slog.String("worker", fc.worker.name))
410+
}
405411

406412
return nil, 0
407413
}
@@ -471,12 +477,13 @@ func splitRawHeader(rawHeader *C.char, length int) (string, string) {
471477

472478
//export go_write_headers
473479
func go_write_headers(threadIndex C.uintptr_t, status C.int, headers *C.zend_llist) C.bool {
474-
fc := phpThreads[threadIndex].getRequestContext()
475-
476-
if fc == nil {
480+
ctx := phpThreads[threadIndex].context()
481+
if ctx == nil {
477482
return C.bool(false)
478483
}
479484

485+
fc := ctx.Value(contextKey).(*frankenPHPContext)
486+
480487
if fc.isDone {
481488
return C.bool(false)
482489
}
@@ -499,13 +506,16 @@ func go_write_headers(threadIndex C.uintptr_t, status C.int, headers *C.zend_lli
499506
// go panics on invalid status code
500507
// https://github.com/golang/go/blob/9b8742f2e79438b9442afa4c0a0139d3937ea33f/src/net/http/server.go#L1162
501508
if goStatus < 100 || goStatus > 999 {
502-
logger.Warn(fmt.Sprintf("Invalid response status code %v", goStatus))
509+
if logger.Enabled(ctx, slog.LevelWarn) {
510+
logger.LogAttrs(ctx, slog.LevelWarn, "Invalid response status code", slog.Int("status_code", goStatus))
511+
}
512+
503513
goStatus = 500
504514
}
505515

506516
fc.responseWriter.WriteHeader(goStatus)
507517

508-
if goStatus >= 100 && goStatus < 200 {
518+
if goStatus < 200 {
509519
// Clear headers, it's not automatically done by ResponseWriter.WriteHeader() for 1xx responses
510520
h := fc.responseWriter.Header()
511521
for k := range h {
@@ -518,25 +528,31 @@ func go_write_headers(threadIndex C.uintptr_t, status C.int, headers *C.zend_lli
518528

519529
//export go_sapi_flush
520530
func go_sapi_flush(threadIndex C.uintptr_t) bool {
521-
fc := phpThreads[threadIndex].getRequestContext()
522-
if fc == nil || fc.responseWriter == nil {
531+
ctx := phpThreads[threadIndex].context()
532+
if ctx == nil {
533+
return false
534+
}
535+
536+
fc := ctx.Value(contextKey).(*frankenPHPContext)
537+
538+
if fc.responseWriter == nil {
523539
return false
524540
}
525541

526542
if fc.clientHasClosed() && !fc.isDone {
527543
return true
528544
}
529545

530-
if err := http.NewResponseController(fc.responseWriter).Flush(); err != nil {
531-
logger.LogAttrs(context.Background(), 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))
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))
532548
}
533549

534550
return false
535551
}
536552

537553
//export go_read_post
538554
func go_read_post(threadIndex C.uintptr_t, cBuf *C.char, countBytes C.size_t) (readBytes C.size_t) {
539-
fc := phpThreads[threadIndex].getRequestContext()
555+
fc := phpThreads[threadIndex].context().Value(contextKey).(*frankenPHPContext)
540556

541557
if fc.responseWriter == nil {
542558
return 0
@@ -555,7 +571,7 @@ func go_read_post(threadIndex C.uintptr_t, cBuf *C.char, countBytes C.size_t) (r
555571

556572
//export go_read_cookies
557573
func go_read_cookies(threadIndex C.uintptr_t) *C.char {
558-
request := phpThreads[threadIndex].getRequestContext().request
574+
request := phpThreads[threadIndex].context().Value(contextKey).(*frankenPHPContext).request
559575
if request == nil {
560576
return nil
561577
}
@@ -599,7 +615,7 @@ func go_log(message *C.char, level C.int) {
599615

600616
//export go_is_context_done
601617
func go_is_context_done(threadIndex C.uintptr_t) C.bool {
602-
return C.bool(phpThreads[threadIndex].getRequestContext().isDone)
618+
return C.bool(phpThreads[threadIndex].context().Value(contextKey).(*frankenPHPContext).isDone)
603619
}
604620

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

phpmainthread_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919
var testDataPath, _ = filepath.Abs("./testdata")
2020

2121
func TestStartAndStopTheMainThreadWithOneInactiveThread(t *testing.T) {
22-
logger = slog.New(slog.NewTextHandler(io.Discard, nil))
22+
logger = slog.New(slog.DiscardHandler)
2323
_, err := initPHPThreads(1, 1, nil) // boot 1 thread
2424
assert.NoError(t, err)
2525

@@ -28,6 +28,7 @@ func TestStartAndStopTheMainThreadWithOneInactiveThread(t *testing.T) {
2828
assert.True(t, phpThreads[0].state.is(stateInactive))
2929

3030
drainPHPThreads()
31+
3132
assert.Nil(t, phpThreads)
3233
}
3334

phpthread.go

Lines changed: 5 additions & 5 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 *frankenPHPContext
19+
requestChan chan context.Context
2020
drainChan chan struct{}
2121
handlerMu sync.Mutex
2222
handler threadHandler
@@ -29,13 +29,13 @@ type threadHandler interface {
2929
name() string
3030
beforeScriptExecution() string
3131
afterScriptExecution(exitStatus int)
32-
getRequestContext() *frankenPHPContext
32+
context() context.Context
3333
}
3434

3535
func newPHPThread(threadIndex int) *phpThread {
3636
return &phpThread{
3737
threadIndex: threadIndex,
38-
requestChan: make(chan *frankenPHPContext),
38+
requestChan: make(chan context.Context),
3939
state: newThreadState(),
4040
}
4141
}
@@ -104,8 +104,8 @@ func (thread *phpThread) transitionToNewHandler() string {
104104
return thread.handler.beforeScriptExecution()
105105
}
106106

107-
func (thread *phpThread) getRequestContext() *frankenPHPContext {
108-
return thread.handler.getRequestContext()
107+
func (thread *phpThread) context() context.Context {
108+
return thread.handler.context()
109109
}
110110

111111
func (thread *phpThread) name() string {

threadinactive.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package frankenphp
22

3+
import "context"
4+
35
// representation of a thread with no work assigned to it
46
// implements the threadHandler interface
57
// each inactive thread weighs around ~350KB
@@ -37,7 +39,7 @@ func (handler *inactiveThread) afterScriptExecution(int) {
3739
panic("inactive threads should not execute scripts")
3840
}
3941

40-
func (handler *inactiveThread) getRequestContext() *frankenPHPContext {
42+
func (handler *inactiveThread) context() context.Context {
4143
return nil
4244
}
4345

threadregular.go

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
package frankenphp
22

33
import (
4+
"context"
45
"sync"
56
)
67

78
// representation of a non-worker PHP thread
89
// executes PHP scripts in a web context
910
// implements the threadHandler interface
1011
type regularThread struct {
11-
state *threadState
12-
thread *phpThread
13-
requestContext *frankenPHPContext
12+
state *threadState
13+
thread *phpThread
14+
ctx context.Context
1415
}
1516

1617
var (
1718
regularThreads []*phpThread
1819
regularThreadMu = &sync.RWMutex{}
19-
regularRequestChan chan *frankenPHPContext
20+
regularRequestChan chan context.Context
2021
)
2122

2223
func convertToRegularThread(thread *phpThread) {
@@ -50,8 +51,8 @@ func (handler *regularThread) afterScriptExecution(int) {
5051
handler.afterRequest()
5152
}
5253

53-
func (handler *regularThread) getRequestContext() *frankenPHPContext {
54-
return handler.requestContext
54+
func (handler *regularThread) context() context.Context {
55+
return handler.ctx
5556
}
5657

5758
func (handler *regularThread) name() string {
@@ -64,30 +65,35 @@ func (handler *regularThread) waitForRequest() string {
6465

6566
handler.state.markAsWaiting(true)
6667

67-
var fc *frankenPHPContext
68+
var ctx context.Context
6869
select {
6970
case <-handler.thread.drainChan:
7071
// go back to beforeScriptExecution
7172
return handler.beforeScriptExecution()
72-
case fc = <-regularRequestChan:
73+
case ctx = <-regularRequestChan:
7374
}
7475

75-
handler.requestContext = fc
76+
handler.ctx = ctx
7677
handler.state.markAsWaiting(false)
7778

7879
// set the scriptFilename that should be executed
79-
return fc.scriptFilename
80+
return ctx.Value(contextKey).(*frankenPHPContext).scriptFilename
8081
}
8182

8283
func (handler *regularThread) afterRequest() {
83-
handler.requestContext.closeContext()
84-
handler.requestContext = nil
84+
fc := handler.ctx.Value(contextKey).(*frankenPHPContext)
85+
86+
fc.closeContext()
87+
handler.ctx = nil
8588
}
8689

87-
func handleRequestWithRegularPHPThreads(fc *frankenPHPContext) error {
90+
func handleRequestWithRegularPHPThreads(ctx context.Context) error {
8891
metrics.StartRequest()
92+
93+
fc := ctx.Value(contextKey).(*frankenPHPContext)
94+
8995
select {
90-
case regularRequestChan <- fc:
96+
case regularRequestChan <- ctx:
9197
// a thread was available to handle the request immediately
9298
<-fc.done
9399
metrics.StopRequest()
@@ -101,7 +107,7 @@ func handleRequestWithRegularPHPThreads(fc *frankenPHPContext) error {
101107
metrics.QueuedRequest()
102108
for {
103109
select {
104-
case regularRequestChan <- fc:
110+
case regularRequestChan <- ctx:
105111
metrics.DequeuedRequest()
106112
<-fc.done
107113
metrics.StopRequest()

threadtasks_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package frankenphp
22

33
import (
4+
"context"
45
"sync"
56
)
67

@@ -60,11 +61,11 @@ func (handler *taskThread) beforeScriptExecution() string {
6061
panic("unexpected state: " + thread.state.name())
6162
}
6263

63-
func (handler *taskThread) afterScriptExecution(int) {
64+
func (handler *taskThread) afterScriptExecution(_ int) {
6465
panic("task threads should not execute scripts")
6566
}
6667

67-
func (handler *taskThread) getRequestContext() *frankenPHPContext {
68+
func (handler *taskThread) context() context.Context {
6869
return nil
6970
}
7071

0 commit comments

Comments
 (0)