diff --git a/runtime/Makefile b/runtime/Makefile index f0816a8..c8d4de4 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -16,6 +16,7 @@ CFLAGS += -D_GNU_SOURCE #CFLAGS += -DNOSTDIO #CFLAGS += -DSTANDALONE CFLAGS += -DUSE_UVIO +#CFLAGS += -DUSE_HTTP_UVIO -DUSE_HTTP_SYNC CFLAGS += -DSBOX_SCALE_ALLOC #CFLAGS += -DUSE_SYSCALL #CFLAGS += -DPREEMPT_DISABLE diff --git a/runtime/include/http.h b/runtime/include/http.h index 04b9e4d..ac0fd09 100644 --- a/runtime/include/http.h +++ b/runtime/include/http.h @@ -4,6 +4,7 @@ #include #include #include +#include /* all in-memory ptrs.. don't mess around with that! */ struct http_header { @@ -34,7 +35,11 @@ struct http_response { int bodylen; char *status; int stlen; +#ifdef USE_HTTP_UVIO uv_buf_t bufs[HTTP_HEADERS_MAX * 2 + 3]; //max headers, one line for status code, remaining for body! +#else + struct iovec bufs[HTTP_HEADERS_MAX * 2 + 3]; +#endif }; #endif /* SFRT_HTTP_H */ diff --git a/runtime/include/http_api.h b/runtime/include/http_api.h index ba7c493..2e99a0d 100644 --- a/runtime/include/http_api.h +++ b/runtime/include/http_api.h @@ -8,7 +8,7 @@ int http_request_parse_sb(struct sandbox *s, size_t l); int http_response_header_set_sb(struct sandbox *s, char *h, int len); int http_response_body_set_sb(struct sandbox *s, char *body, int len); int http_response_status_set_sb(struct sandbox *s, char *status, int len); -int http_response_uv_sb(struct sandbox *s); +int http_response_vector_sb(struct sandbox *s); void http_init(void); @@ -37,9 +37,9 @@ http_response_status_set(char *status, int len) } static inline int -http_response_uv(void) +http_response_vector(void) { - return http_response_uv_sb(sandbox_current()); + return http_response_vector_sb(sandbox_current()); } static inline int diff --git a/runtime/include/sandbox.h b/runtime/include/sandbox.h index e4b99c0..5e348d2 100644 --- a/runtime/include/sandbox.h +++ b/runtime/include/sandbox.h @@ -193,9 +193,12 @@ sandbox_args(void) //void sandbox_run(struct sandbox *s); void *sandbox_run_func(void *data); -struct sandbox *sandbox_schedule(void); +struct sandbox *sandbox_schedule(int interrupt); void sandbox_block(void); void sandbox_wakeup(sandbox_t *sb); +// called in sandbox_entry() before and after fn() execution +// for http request/response processing using uvio +void sandbox_block_http(void); void sandbox_response(void); // should be the entry-point for each sandbox so it can do per-sandbox mem/etc init. diff --git a/runtime/include/types.h b/runtime/include/types.h index b2e34a6..27d5839 100644 --- a/runtime/include/types.h +++ b/runtime/include/types.h @@ -116,7 +116,7 @@ typedef enum { #define JSON_ELE_MAX 16 // FIXME: some naive work-stealing here.. -#define SBOX_PULL_MAX 16 +#define SBOX_PULL_MAX 1 #define SBOX_MAX_OPEN 32 #define SBOX_PREOPEN_MAGIC (707707707) // reads lol lol lol upside down diff --git a/runtime/src/http.c b/runtime/src/http.c index 17a3fb4..806de88 100644 --- a/runtime/src/http.c +++ b/runtime/src/http.c @@ -163,12 +163,13 @@ http_response_status_set_sb(struct sandbox *c, char *status, int len) } int -http_response_uv_sb(struct sandbox *c) +http_response_vector_sb(struct sandbox *c) { int nb = 0; #ifndef STANDALONE struct http_response *r = &c->rsi; +#ifdef USE_HTTP_UVIO r->bufs[nb] = uv_buf_init(r->status, r->stlen); nb++; @@ -183,6 +184,27 @@ http_response_uv_sb(struct sandbox *c) r->bufs[nb] = uv_buf_init(r->status + r->stlen - 2, 2); //for crlf nb++; } +#else + r->bufs[nb].iov_base = r->status; + r->bufs[nb].iov_len = r->stlen; + nb++; + + for (int i = 0; i < r->nheaders; i++) { + r->bufs[nb].iov_base = r->headers[i].hdr; + r->bufs[nb].iov_len = r->headers[i].len; + nb++; + } + + if (r->body) { + r->bufs[nb].iov_base = r->body; + r->bufs[nb].iov_len = r->bodylen; + nb++; + + r->bufs[nb].iov_base = r->status + r->stlen - 2; + r->bufs[nb].iov_len = 2; + nb++; + } +#endif #endif return nb; diff --git a/runtime/src/runtime.c b/runtime/src/runtime.c index 7ff4347..4683eda 100644 --- a/runtime/src/runtime.c +++ b/runtime/src/runtime.c @@ -87,10 +87,12 @@ sandbox_io_nowait(void) } struct sandbox * -sandbox_schedule(void) +sandbox_schedule(int interrupt) { struct sandbox *s = NULL; if (ps_list_head_empty(&runq)) { + // this is in an interrupt context, don't steal work here! + if (interrupt) return NULL; if (sandbox_pull() == 0) { //debuglog("[null: null]\n"); return NULL; @@ -130,7 +132,7 @@ sandbox_schedule_io(void) if (!in_callback) sandbox_io_nowait(); softint_disable(); - struct sandbox *s = sandbox_schedule(); + struct sandbox *s = sandbox_schedule(0); softint_enable(); assert(s == NULL || s->state == SANDBOX_RUNNABLE); @@ -143,11 +145,12 @@ sandbox_wakeup(sandbox_t *s) #ifndef STANDALONE softint_disable(); debuglog("[%p: %s]\n", s, s->mod->name); - // perhaps 2 lists in the sandbox to make sure sandbox is either in runlist or waitlist.. + if (s->state != SANDBOX_BLOCKED) goto done; assert(s->state == SANDBOX_BLOCKED); assert(ps_list_singleton_d(s)); s->state = SANDBOX_RUNNABLE; ps_list_head_append_d(&runq, s); +done: softint_enable(); #endif } @@ -156,13 +159,12 @@ void sandbox_block(void) { #ifndef STANDALONE - // perhaps 2 lists in the sandbox to make sure sandbox is either in runlist or waitlist.. assert(in_callback == 0); softint_disable(); struct sandbox *c = sandbox_current(); ps_list_rem_d(c); c->state = SANDBOX_BLOCKED; - struct sandbox *s = sandbox_schedule(); + struct sandbox *s = sandbox_schedule(0); debuglog("[%p: %s, %p: %s]\n", c, c->mod->name, s, s ? s->mod->name: ""); softint_enable(); sandbox_switch(s); @@ -171,6 +173,24 @@ sandbox_block(void) #endif } +void +sandbox_block_http(void) +{ +#ifdef USE_HTTP_UVIO +#ifdef USE_HTTP_SYNC + // realistically, we're processing all async I/O on this core when a sandbox blocks on http processing, not great! + // if there is a way (TODO), perhaps RUN_ONCE and check if your I/O is processed, if yes, return + // else do async block! + uv_run(runtime_uvio(), UV_RUN_DEFAULT); +#else + sandbox_block(); +#endif +#else + assert(0); + //it should not be called if not using uvio for http +#endif +} + void __attribute__((noinline)) __attribute__((noreturn)) sandbox_switch_preempt(void) { @@ -248,7 +268,7 @@ sandbox_exit(void) sandbox_local_stop(curr); curr->state = SANDBOX_RETURNED; // free resources from "main function execution", as stack still in use. - struct sandbox *n = sandbox_schedule(); + struct sandbox *n = sandbox_schedule(0); assert(n != curr); softint_enable(); //sandbox_local_end(curr); diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index 4502ed6..b854d04 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -133,11 +133,11 @@ sandbox_client_request_get(void) struct sandbox *curr = sandbox_current(); curr->rr_data_len = 0; -#ifndef USE_UVIO +#ifndef USE_HTTP_UVIO int r = 0; r = recv(curr->csock, (curr->req_resp_data), curr->mod->max_req_sz, 0); if (r <= 0) { - perror("recv"); + if (r < 0) perror("recv1"); return r; } while (r > 0) { @@ -148,13 +148,13 @@ sandbox_client_request_get(void) r = recv(curr->csock, (curr->req_resp_data + r), curr->mod->max_req_sz - r, 0); if (r < 0) { - perror("recv"); + perror("recv2"); return r; } } #else int r = uv_read_start((uv_stream_t *)&curr->cuv, sb_alloc_callback, sb_read_callback); - sandbox_block(); + sandbox_block_http(); if (curr->rr_data_len == 0) return 0; #endif @@ -170,15 +170,6 @@ sandbox_client_response_set(void) #ifndef STANDALONE struct sandbox *curr = sandbox_current(); -#ifndef USE_UVIO - strcpy(curr->req_resp_data + curr->rr_data_len, "HTTP/1.1 200 OK\r\n"); - - // TODO: response set in req_resp_data - curr->rr_data_len += strlen("HTTP/1.1 200 OK\r\n"); - - int r = send(curr->csock, curr->req_resp_data, curr->rr_data_len, 0); - if (r < 0) perror("send"); -#else int bodylen = curr->rr_data_len; if (bodylen > 0) { http_response_body_set(curr->req_resp_data, bodylen); @@ -217,10 +208,14 @@ sandbox_client_response_set(void) curr->rr_data_len += strlen("HTTP/1.1 200 OK\r\n"); http_response_status_set(st, strlen("HTTP/1.1 200 OK\r\n")); + int n = http_response_vector(); +#ifndef USE_HTTP_UVIO + int r = writev(curr->csock, curr->rsi.bufs, n); + if (r < 0) perror("writev"); +#else uv_write_t req = { .data = curr, }; - int n = http_response_uv(); int r = uv_write(&req, (uv_stream_t *)&curr->cuv, curr->rsi.bufs, n, sb_write_callback); - sandbox_block(); + sandbox_block_http(); #endif return r; #else @@ -253,7 +248,11 @@ sandbox_entry(void) #ifndef STANDALONE http_parser_init(&curr->hp, HTTP_REQUEST); curr->hp.data = curr; -#ifdef USE_UVIO +#ifdef USE_HTTP_UVIO +#ifndef USE_UVIO + printf("UVIO not enabled!\n"); + assert(0); +#endif int r = uv_tcp_init(runtime_uvio(), (uv_tcp_t *)&curr->cuv); assert(r == 0); curr->cuv.data = curr; @@ -277,9 +276,9 @@ sandbox_entry(void) } #ifndef STANDALONE -#ifdef USE_UVIO +#ifdef USE_HTTP_UVIO uv_close((uv_handle_t *)&curr->cuv, sb_close_callback); - sandbox_block(); + sandbox_block_http(); #else close(curr->csock); #endif diff --git a/runtime/src/softint.c b/runtime/src/softint.c index dff8011..bf3b50c 100644 --- a/runtime/src/softint.c +++ b/runtime/src/softint.c @@ -67,7 +67,7 @@ softint_alarm_schedule(void *u) if (curr == NULL) goto done; // find a next sandbox to run.. - struct sandbox *next = sandbox_schedule(); + struct sandbox *next = sandbox_schedule(1); if (next == NULL) goto done; if (next == curr) goto done; // only this sandbox to schedule.. return to it! // save the current sandbox, state from uc!