From e5118c9c2e382a5a618e7190407d5486d8a5e1e4 Mon Sep 17 00:00:00 2001 From: ading2210 Date: Tue, 19 Mar 2024 13:45:21 -0400 Subject: [PATCH] not yet working coroutines --- README.md | 4 +- client/build.sh | 4 +- client/javascript/ftp.js | 2 +- client/javascript/session.js | 5 +-- client/libcurl/session.c | 81 +++++++++++++++++++++++++++++++++++- client/libcurl/types.h | 4 ++ client/tools/all_deps.sh | 7 +++- client/tools/minicoro.sh | 6 +++ 8 files changed, 102 insertions(+), 11 deletions(-) create mode 100755 client/tools/minicoro.sh diff --git a/README.md b/README.md index 62336b7..8fb281b 100644 --- a/README.md +++ b/README.md @@ -104,8 +104,8 @@ To create new sessions for HTTP requests, use the `libcurl.HTTPSession` class. T - `options` - An optional object with various settings. The valid HTTP session settings are: -- `enable_cookies` - A boolean which indicate whether or not cookies should be persisted within the session. -- `cookie_jar` - A blob containing the data in the cookie jar file. This should have been exported from a previous session. +- `enable_cookies` - A boolean which indicate whether or not cookies should be persisted within the session. NOT IMPLEMENTED YET +- `cookie_jar` - A blob containing the data in the cookie jar file. This should have been exported from a previous session. NOT IMPLEMENTED YET ### Creating WebSocket Connections: To use WebSockets, create a `libcurl.CurlWebSocket` object, which takes the following arguments: diff --git a/client/build.sh b/client/build.sh index 8cb15d8..7b71c0b 100755 --- a/client/build.sh +++ b/client/build.sh @@ -27,8 +27,8 @@ EXPORTED_FUNCS="${EXPORTED_FUNCS:1}" #compile options RUNTIME_METHODS="addFunction,removeFunction,allocate,ALLOC_NORMAL" -COMPILER_OPTIONS="-o $MODULE_FILE -lcurl -lssl -lcrypto -lcjson -lz -lbrotlidec -lbrotlicommon -lnghttp2 -I $INCLUDE_DIR -L $LIB_DIR" -EMSCRIPTEN_OPTIONS="-lwebsocket.js -sENVIRONMENT=worker,web -sASSERTIONS=1 -sLLD_REPORT_UNDEFINED -sALLOW_TABLE_GROWTH -sALLOW_MEMORY_GROWTH -sEXPORTED_FUNCTIONS=$EXPORTED_FUNCS -sEXPORTED_RUNTIME_METHODS=$RUNTIME_METHODS" +COMPILER_OPTIONS="-o $MODULE_FILE -lcurl -lssl -lcrypto -lcjson -lz -lbrotlidec -lbrotlicommon -lnghttp2 -I $INCLUDE_DIR -L $LIB_DIR -Wl,--wrap=poll" +EMSCRIPTEN_OPTIONS="-lwebsocket.js -sASYNCIFY -sENVIRONMENT=worker,web -sASSERTIONS=1 -sLLD_REPORT_UNDEFINED -sALLOW_TABLE_GROWTH -sALLOW_MEMORY_GROWTH -sEXPORTED_FUNCTIONS=$EXPORTED_FUNCS -sEXPORTED_RUNTIME_METHODS=$RUNTIME_METHODS" #clean output dir rm -rf $OUT_DIR diff --git a/client/javascript/ftp.js b/client/javascript/ftp.js index 6978905..c067279 100644 --- a/client/javascript/ftp.js +++ b/client/javascript/ftp.js @@ -3,7 +3,7 @@ class FTPSession extends CurlSession { if (!url.startsWith("ftp://") && !url.startsWith("ftps://")) { throw "invalid url protocol"; } - super(); + super(1); this.url = url; this.options = options; diff --git a/client/javascript/session.js b/client/javascript/session.js index e2911f3..e979a3b 100644 --- a/client/javascript/session.js +++ b/client/javascript/session.js @@ -1,9 +1,8 @@ class CurlSession { - constructor(options={}) { + constructor(need_fiber=0) { check_loaded(true); - this.options = options; - this.session_ptr = _session_create(); + this.session_ptr = _session_create(need_fiber); this.active_requests = 0; this.event_loop = null; this.requests_list = []; diff --git a/client/libcurl/session.c b/client/libcurl/session.c index 059f844..795f204 100644 --- a/client/libcurl/session.c +++ b/client/libcurl/session.c @@ -1,4 +1,5 @@ #include +#include #include "curl/multi.h" #include "curl/curl.h" @@ -6,15 +7,24 @@ #include "types.h" #include "request.h" #include "util.h" +#include "context.h" -struct SessionInfo* session_create() { +#define MINICORO_IMPL +#include "minicoro.h" + +struct SessionInfo* running_session; + +struct SessionInfo* session_create(int need_fiber) { struct SessionInfo *session = malloc(sizeof(struct SessionInfo)); session->multi_handle = curl_multi_init(); session->request_active = 0; + session->need_fiber = need_fiber; + session->fiber_running = 0; + session->fiber = NULL; return session; } -void session_perform(struct SessionInfo *session) { +void session_thread(struct SessionInfo *session) { CURLMcode mc; session->request_active = 0; mc = curl_multi_perform(session->multi_handle, &session->request_active); @@ -25,6 +35,68 @@ void session_perform(struct SessionInfo *session) { if (curl_msg && curl_msg->msg == CURLMSG_DONE) { finish_request(curl_msg); } + + //suspend the coroutine if there are no requests active + if (session->need_fiber && !session->request_active) { + mco_yield(mco_running()); + } +} + +void session_thread_wrapper(mco_coro* fiber) { + //infinitely loop here so we don't need to keep remaking the coroutine + while (1) { + session_thread(fiber->user_data); + } +} + +void session_perform(struct SessionInfo *session) { + running_session = session; + if (!session->need_fiber) { + session_thread(session); + return; + } + + //create a new coroutine if there isn't one running already + mco_coro* fiber; + if (!session->fiber_running) { + mco_desc desc = mco_desc_init(session_thread_wrapper, 0); + desc.user_data = session; + mco_result res = mco_create(&fiber, &desc); + } + else { + fiber = session->fiber; + } + + if (mco_status(fiber) == MCO_SUSPENDED) { + printf("fiber suspended \n"); + } + if (mco_status(fiber) == MCO_DEAD) { + printf("fiber dead \n"); + } + if (mco_status(fiber) == MCO_NORMAL) { + printf("fiber normal \n"); + } + + //swich contexts into coroutine + session->fiber_running = 1; + mco_resume(fiber); +} + + +//wrap the poll function +//we want to switch contexts when curl is polling the socket +extern int __real_poll(struct pollfd *fds, nfds_t nfds, int timeout); +int __wrap_poll(struct pollfd *fds, nfds_t nfds, int timeout) { + int ret = __real_poll(fds, nfds, timeout); + + //don't switch contexts if there is activity on the socket + if (!running_session->need_fiber || ret != 0) { + return ret; + } + + //perform the context switch if there is nothing on the socket + mco_yield(mco_running()); + return ret; } void session_set_options(struct SessionInfo *session, int connections_limit, int cache_limit) { @@ -49,4 +121,9 @@ void session_remove_request(struct SessionInfo *session, CURL* http_handle) { void session_cleanup(struct SessionInfo *session) { curl_multi_cleanup(session->multi_handle); + + if (session->fiber != NULL) + mco_destroy(session->fiber); + + free(session); } \ No newline at end of file diff --git a/client/libcurl/types.h b/client/libcurl/types.h index a0642bd..8f7724d 100644 --- a/client/libcurl/types.h +++ b/client/libcurl/types.h @@ -1,4 +1,5 @@ #include "curl/curl.h" +#include "minicoro.h" typedef void(*DataCallback)(char* chunk_ptr, int chunk_size); typedef void(*EndCallback)(int error); @@ -24,4 +25,7 @@ struct WSResult { struct SessionInfo { CURLM* multi_handle; int request_active; + int need_fiber; + int fiber_running; + mco_coro* fiber; }; \ No newline at end of file diff --git a/client/tools/all_deps.sh b/client/tools/all_deps.sh index 6e0cebd..521b5f9 100755 --- a/client/tools/all_deps.sh +++ b/client/tools/all_deps.sh @@ -11,6 +11,7 @@ CURL_PREFIX=$(realpath build/curl-wasm) ZLIB_PREFIX=$(realpath build/zlib-wasm) BROTLI_PREFIX=$(realpath build/brotli-wasm) NGHTTP2_PREFIX=$(realpath build/nghttp2-wasm) +MINICORO_PREFIX=$(realpath build/minicoro-wasm) if [ ! -d $OPENSSL_PREFIX ]; then tools/openssl.sh @@ -30,9 +31,13 @@ fi if [ ! -d $CURL_PREFIX ]; then tools/curl.sh fi +if [ ! -d $MINICORO_PREFIX ]; then + tools/minicoro.sh +fi cp -r $OPENSSL_PREFIX/* $CURL_PREFIX cp -r $CJSON_PREFIX/* $CURL_PREFIX cp -r $ZLIB_PREFIX/* $CURL_PREFIX cp -r $BROTLI_PREFIX/* $CURL_PREFIX -cp -r $NGHTTP2_PREFIX/* $CURL_PREFIX \ No newline at end of file +cp -r $NGHTTP2_PREFIX/* $CURL_PREFIX +cp -r $MINICORO_PREFIX/* $CURL_PREFIX \ No newline at end of file diff --git a/client/tools/minicoro.sh b/client/tools/minicoro.sh new file mode 100755 index 0000000..7c0d150 --- /dev/null +++ b/client/tools/minicoro.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +#download the minicoro library + +mkdir -p build/minicoro-wasm/include/ +wget "https://raw.githubusercontent.com/edubart/minicoro/main/minicoro.h" -O build/minicoro-wasm/include/minicoro.h \ No newline at end of file