diff --git a/lang/el-compiler/runtime/el_platform_win.h b/lang/el-compiler/runtime/el_platform_win.h index 12d417b..88204a0 100644 --- a/lang/el-compiler/runtime/el_platform_win.h +++ b/lang/el-compiler/runtime/el_platform_win.h @@ -48,7 +48,7 @@ /* ── socket close ─────────────────────────────────────────────────────────── */ /* Winsock closes sockets with closesocket(), not close() (close() is for file fds). The POSIX build defines the same helper as close() so the call sites are identical across platforms. */ -static inline int el_closesocket(int s) { return closesocket((SOCKET)s); } +static inline int el_closesocket(SOCKET s) { return closesocket(s); } /* ── winsock init (once, at load) ─────────────────────────────────────────── */ static void el__win_net_init(void) { @@ -76,12 +76,35 @@ static inline void* el_win_dlsym(void* handle, const char* name) { #define mkdir(path, mode) _mkdir(path) /* POSIX mkdir(path,mode) → _mkdir(path) */ #define timegm _mkgmtime /* UTC tm → time_t */ -/* setenv/unsetenv: not in the Windows CRT; map to _putenv_s. */ +/* setenv/unsetenv: not in the Windows CRT; map to _putenv_s / SetEnvironmentVariable. */ static inline int setenv(const char* name, const char* value, int overwrite) { (void)overwrite; return _putenv_s(name, value ? value : ""); } -static inline int unsetenv(const char* name) { return _putenv_s(name, ""); } +static inline int unsetenv(const char* name) { + /* _putenv_s(name, "") sets VAR="" rather than removing it. + * SetEnvironmentVariableA(name, NULL) truly deletes it from the Win32 + * env block; then we sync the CRT cache with _putenv("NAME="). */ + SetEnvironmentVariableA(name, NULL); + size_t len = strlen(name); + char *buf = (char*)malloc(len + 2); + if (!buf) return -1; + memcpy(buf, name, len); + buf[len] = '='; + buf[len + 1] = '\0'; + _putenv(buf); + free(buf); + return 0; +} + +/* nanosleep — not available in MSVC/UCRT; approximate with Sleep(). */ +static inline int el_nanosleep(const struct timespec *req, struct timespec *rem) { + (void)rem; + DWORD ms = (DWORD)((req->tv_sec * 1000ULL) + (req->tv_nsec / 1000000ULL)); + Sleep(ms ? ms : 1); + return 0; +} +#define nanosleep(req, rem) el_nanosleep((req), (rem)) /* localtime_r/gmtime_r: Windows offers localtime_s/gmtime_s with reversed arg order. */ static inline struct tm* localtime_r(const time_t* t, struct tm* out) { diff --git a/lang/el-compiler/runtime/el_runtime.c b/lang/el-compiler/runtime/el_runtime.c index 4faf72a..f19b266 100644 --- a/lang/el-compiler/runtime/el_runtime.c +++ b/lang/el-compiler/runtime/el_runtime.c @@ -1061,7 +1061,6 @@ el_val_t http_post_to_file(el_val_t url, el_val_t body, el_val_t headers_map, el #define HTTP_MAX_CONNS 64 -typedef el_val_t (*http_handler_fn)(el_val_t method, el_val_t path, el_val_t body); typedef struct { char* name; @@ -1536,12 +1535,20 @@ static void http_send_response(int fd, const char* body) { } typedef struct { +#ifdef _WIN32 + SOCKET fd; +#else int fd; +#endif } HttpWorkerArg; static void* http_worker(void* arg) { HttpWorkerArg* a = (HttpWorkerArg*)arg; +#ifdef _WIN32 + SOCKET fd = a->fd; +#else int fd = a->fd; +#endif free(a); char *method = NULL, *path = NULL, *body = NULL; if (http_read_request(fd, &method, &path, &body, NULL) == 0) { @@ -1573,7 +1580,7 @@ static void* http_worker(void* arg) { free(response); } free(method); free(path); free(body); - close(fd); + el_closesocket(fd); /* release a slot */ pthread_mutex_lock(&_http_conn_mu); _http_conn_active--; @@ -1610,7 +1617,11 @@ el_val_t http_serve(el_val_t port, el_val_t handler) { while (1) { struct sockaddr_in6 cli; socklen_t clen = sizeof(cli); +#ifdef _WIN32 + SOCKET cfd = accept(sock, (struct sockaddr*)&cli, &clen); +#else int cfd = accept(sock, (struct sockaddr*)&cli, &clen); +#endif if (cfd < 0) { if (errno == EINTR) continue; perror("accept"); break; @@ -1656,8 +1667,6 @@ el_val_t http_serve(el_val_t port, el_val_t handler) { * separate active-handler slot, separate dlsym fallback. Mixing v1 and v2 * handlers in the same process is fine — they don't share the active slot. */ -typedef el_val_t (*http_handler4_fn)(el_val_t method, el_val_t path, - el_val_t headers_map, el_val_t body); typedef struct { char* name; @@ -1793,7 +1802,11 @@ static el_val_t http_build_headers_map(const char* hdr_block) { static void* http_worker_v2(void* arg) { HttpWorkerArg* a = (HttpWorkerArg*)arg; +#ifdef _WIN32 + SOCKET fd = a->fd; +#else int fd = a->fd; +#endif free(a); char *method = NULL, *path = NULL, *body = NULL, *hdr_block = NULL; if (http_read_request(fd, &method, &path, &body, &hdr_block) == 0) { @@ -1823,7 +1836,7 @@ static void* http_worker_v2(void* arg) { free(response); } free(method); free(path); free(body); free(hdr_block); - close(fd); + el_closesocket(fd); pthread_mutex_lock(&_http_conn_mu); _http_conn_active--; pthread_cond_signal(&_http_conn_cv); @@ -1860,7 +1873,11 @@ el_val_t http_serve_v2(el_val_t port, el_val_t handler) { while (1) { struct sockaddr_in6 cli; socklen_t clen = sizeof(cli); +#ifdef _WIN32 + SOCKET cfd = accept(sock, (struct sockaddr*)&cli, &clen); +#else int cfd = accept(sock, (struct sockaddr*)&cli, &clen); +#endif if (cfd < 0) { if (errno == EINTR) continue; perror("accept"); break;