spawn new thread per connection, add yaml for docs and also add GSI to readme
This commit is contained in:
48
http.odin
48
http.odin
@@ -6,6 +6,7 @@ import vmem "core:mem/virtual"
|
||||
import "core:net"
|
||||
import "core:strings"
|
||||
import "core:strconv"
|
||||
import "core:thread"
|
||||
|
||||
// HTTP Method enumeration
|
||||
HTTP_Method :: enum {
|
||||
@@ -100,7 +101,6 @@ response_set_body :: proc(resp: ^HTTP_Response, data: []byte) {
|
||||
}
|
||||
|
||||
// Request handler function type
|
||||
// Takes context pointer, request, and request-scoped allocator
|
||||
Request_Handler :: #type proc(ctx: rawptr, request: ^HTTP_Request, request_alloc: mem.Allocator) -> HTTP_Response
|
||||
|
||||
// Server configuration
|
||||
@@ -122,6 +122,13 @@ default_server_config :: proc() -> Server_Config {
|
||||
}
|
||||
}
|
||||
|
||||
// Connection task data - passed to worker threads
|
||||
Connection_Task_Data :: struct {
|
||||
server: ^Server,
|
||||
conn: net.TCP_Socket,
|
||||
source: net.Endpoint,
|
||||
}
|
||||
|
||||
// Server
|
||||
Server :: struct {
|
||||
allocator: mem.Allocator,
|
||||
@@ -168,9 +175,9 @@ server_start :: proc(server: ^Server) -> bool {
|
||||
server.socket = socket
|
||||
server.running = true
|
||||
|
||||
fmt.printfln("HTTP server listening on %v", server.endpoint)
|
||||
fmt.printfln("HTTP server listening on %v (thread-per-connection)", server.endpoint)
|
||||
|
||||
// Accept loop
|
||||
// Accept loop - spawn a thread for each connection
|
||||
for server.running {
|
||||
conn, source, accept_err := net.accept_tcp(socket)
|
||||
if accept_err != nil {
|
||||
@@ -180,9 +187,24 @@ server_start :: proc(server: ^Server) -> bool {
|
||||
continue
|
||||
}
|
||||
|
||||
// Handle connection in separate goroutine would go here
|
||||
// For now, handle synchronously (should spawn thread)
|
||||
handle_connection(server, conn, source)
|
||||
// Allocate connection data
|
||||
conn_data := new(Connection_Task_Data, server.allocator)
|
||||
conn_data.server = server
|
||||
conn_data.conn = conn
|
||||
conn_data.source = source
|
||||
|
||||
// Spawn a new thread for this connection
|
||||
t := thread.create(connection_worker_thread)
|
||||
if t != nil {
|
||||
t.init_context = context
|
||||
t.data = conn_data
|
||||
thread.start(t)
|
||||
// Thread will clean itself up when done
|
||||
} else {
|
||||
// Failed to create thread, close connection
|
||||
net.close(conn)
|
||||
free(conn_data, server.allocator)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -190,12 +212,24 @@ server_start :: proc(server: ^Server) -> bool {
|
||||
|
||||
server_stop :: proc(server: ^Server) {
|
||||
server.running = false
|
||||
|
||||
// Close listening socket
|
||||
if sock, ok := server.socket.?; ok {
|
||||
net.close(sock)
|
||||
server.socket = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Worker thread procedure
|
||||
connection_worker_thread :: proc(t: ^thread.Thread) {
|
||||
defer thread.destroy(t) // Clean up thread when done
|
||||
|
||||
conn_data := cast(^Connection_Task_Data)t.data
|
||||
defer free(conn_data, conn_data.server.allocator)
|
||||
|
||||
handle_connection(conn_data.server, conn_data.conn, conn_data.source)
|
||||
}
|
||||
|
||||
// Handle a single connection
|
||||
handle_connection :: proc(server: ^Server, conn: net.TCP_Socket, source: net.Endpoint) {
|
||||
defer net.close(conn)
|
||||
@@ -214,7 +248,7 @@ handle_connection :: proc(server: ^Server, conn: net.TCP_Socket, source: net.End
|
||||
|
||||
request_alloc := vmem.arena_allocator(&arena)
|
||||
|
||||
// TODO: Double check if we want *all* downstream allocations to use the request arena?
|
||||
// Set request arena as context allocator for downstream allocations
|
||||
old := context.allocator
|
||||
context.allocator = request_alloc
|
||||
defer context.allocator = old
|
||||
|
||||
Reference in New Issue
Block a user