From 1eeb107c98a718394f1c62bc34a79755096ec298 Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Tue, 14 May 2024 15:06:38 +0200 Subject: [PATCH 1/8] Adding an implementation of the aio.c using EPOLL in Linux. Avoiding the limit of file descriptors --- extracted/vm/src/unix/aio.c | 448 +++++++++++++++++++++--------------- 1 file changed, 267 insertions(+), 181 deletions(-) diff --git a/extracted/vm/src/unix/aio.c b/extracted/vm/src/unix/aio.c index 8304366213..1b3affc5f1 100644 --- a/extracted/vm/src/unix/aio.c +++ b/extracted/vm/src/unix/aio.c @@ -30,6 +30,9 @@ * Last edited: Tue Mar 29 13:06:00 PDT 2016 */ +/* Multiple changes and authors performed, use the git versioning tool to correctly address them + */ + #include "pharovm/debug.h" #include "pharovm/semaphores/platformSemaphore.h" #include "sqMemoryFence.h" @@ -45,24 +48,42 @@ #include #include #include -#include +#include #include #include -#define _DO_FLAG_TYPE() do { _DO(AIO_R, rd) _DO(AIO_W, wr) _DO(AIO_X, ex) } while (0) +#define INCOMING_EVENTS_SIZE 50 + +/* + * This is the struct that I am keeping for the registered FD + */ +typedef struct _AioUnixDescriptor { + + int fd; + void* clientData; + aioHandler readHandlerFn; + aioHandler writeHandlerFn; + struct _AioUnixDescriptor* next; + int mask; -static aioHandler rdHandler[FD_SETSIZE]; -static aioHandler wrHandler[FD_SETSIZE]; -static aioHandler exHandler[FD_SETSIZE]; +} AioUnixDescriptor; -static void *clientData[FD_SETSIZE]; +/* + * I have to keep a list of the registered FDs as the operations are divided in two functions + */ +AioUnixDescriptor* descriptorList = NULL; + +/* + * I can access the elements in the list + */ +AioUnixDescriptor* AioUnixDescriptor_find(int fd); +void AioUnixDescriptor_remove(int fd); +void AioUnixDescriptor_removeAll(); -static int maxFd; -static fd_set fdMask; /* handled by aio */ -static fd_set rdMask; /* handle read */ -static fd_set wrMask; /* handle write */ -static fd_set exMask; /* handle exception */ -static fd_set xdMask; /* external descriptor */ +/* + * This is descriptor epoll uses in the poll of the events. + */ +int epollDescriptor = -1; /* * This is important, the AIO poll should only do a long pause if there is no pending signals for semaphores. @@ -81,33 +102,25 @@ int aio_request_interrupt = 0; volatile int isPooling = 0; -static void -undefinedHandler(int fd, void *clientData, int flags) -{ - logError("Undefined handler called (fd %d, flags %x)\n", fd, flags); -} - /* initialise asynchronous i/o */ int signal_pipe_fd[2]; +void sigIOHandler(int signum){ + forceInterruptCheck(); +} + void aioInit(void) { int arg; - + struct epoll_event ev; + interruptFIFOMutex = platform_semaphore_new(1); - FD_ZERO(&fdMask); - FD_ZERO(&rdMask); - FD_ZERO(&wrMask); - FD_ZERO(&exMask); - FD_ZERO(&xdMask); - maxFd = 0; - if (pipe(signal_pipe_fd) != 0) { - logErrorFromErrno("pipe"); - exit(-1); + logErrorFromErrno("pipe"); + exit(-1); } if ((arg = fcntl(signal_pipe_fd[0], F_GETFL, 0)) < 0) @@ -120,30 +133,35 @@ aioInit(void) if (fcntl(signal_pipe_fd[1], F_SETFL, arg | O_NONBLOCK | O_ASYNC | O_APPEND) < 0) logErrorFromErrno("fcntl(F_SETFL, O_ASYNC)"); + epollDescriptor = epoll_create1(0); + if (epollDescriptor == -1) { + logErrorFromErrno("epoll_create1"); + exit(-1); + } - signal(SIGIO, forceInterruptCheck); -} + ev.events = EPOLLIN; + ev.data.ptr = NULL; + + if (epoll_ctl(epollDescriptor, EPOLL_CTL_ADD, signal_pipe_fd[0], &ev) == -1) { + logErrorFromErrno("epoll_ctl: signal_pipe_fd[0]"); + exit(-1); + } + signal(SIGIO, sigIOHandler); +} /* disable handlers and close all handled non-exteral descriptors */ void aioFini(void) { - int fd; - - for (fd = 0; fd < maxFd; fd++) - if (FD_ISSET(fd, &fdMask) && !(FD_ISSET(fd, &xdMask))) { - aioDisable(fd); - close(fd); - FD_CLR(fd, &fdMask); - FD_CLR(fd, &rdMask); - FD_CLR(fd, &wrMask); - FD_CLR(fd, &exMask); - } - while (maxFd && !FD_ISSET(maxFd - 1, &fdMask)) - --maxFd; - signal(SIGPIPE, SIG_DFL); + if(epollDescriptor != -1){ + close(epollDescriptor); + epollDescriptor = -1; + } + + AioUnixDescriptor_removeAll(); + signal(SIGIO, SIG_DFL); } @@ -217,110 +235,75 @@ aioPoll(long microSeconds){ } static int -aio_handle_events(long microSeconds){ - int fd; - fd_set rd, wr, ex; - unsigned long long us; - int maxFdToUse; - long remainingMicroSeconds; - - /* - * Copy the Masks as they are used to know which - * FD wants which event - */ - rd = rdMask; - wr = wrMask; - ex = exMask; - us = ioUTCMicroseconds(); +aio_handle_events(long microSecondsTimeout){ - remainingMicroSeconds = microSeconds; + struct epoll_event incomingEvents[INCOMING_EVENTS_SIZE]; + int epollReturn; + int withError = 0; + AioUnixDescriptor* triggeredDescriptor; - FD_SET(signal_pipe_fd[0], &rd); + long milliSecondsTimeout = microSecondsTimeout / 1000; - maxFdToUse = maxFd > (signal_pipe_fd[0] + 1) ? maxFd : signal_pipe_fd[0] + 1; + //I notify the heartbeat of a pause + heartbeat_poll_enter(microSecondsTimeout); sqLowLevelMFence(); isPooling = 1; - heartbeat_poll_enter(microSeconds); - for (;;) { - struct timeval tv; - int n; - unsigned long long now; + epollReturn = epoll_wait(epollDescriptor, incomingEvents, INCOMING_EVENTS_SIZE, milliSecondsTimeout); - tv.tv_sec = remainingMicroSeconds / 1000000; - tv.tv_usec = remainingMicroSeconds % 1000000; + sqLowLevelMFence(); + isPooling = 0; - n = select(maxFdToUse, &rd, &wr, &ex, &tv); + interruptFIFOMutex->wait(interruptFIFOMutex); + pendingInterruption = false; + interruptFIFOMutex->signal(interruptFIFOMutex); - if (n > 0) - break; - if (n == 0) { - if (remainingMicroSeconds) - addIdleUsecs(remainingMicroSeconds); + //I notify the heartbeat of the end of the pause + heartbeat_poll_exit(microSecondsTimeout); + aio_flush_pipe(signal_pipe_fd[0]); - sqLowLevelMFence(); - isPooling = 0; - heartbeat_poll_exit(microSeconds); - return 0; - } - if (errno && (EINTR != errno)) { - logError("errno %d\n", errno); - logErrorFromErrno("select"); - - sqLowLevelMFence(); - isPooling = 0; - heartbeat_poll_exit(microSeconds); - return 0; + if(epollReturn == -1){ + if(errno != EINTR){ + logErrorFromErrno("epoll_wait"); } - now = ioUTCMicroseconds(); - remainingMicroSeconds -= max(now - us, 1); - - if (remainingMicroSeconds <= 0){ - sqLowLevelMFence(); - isPooling = 0; - heartbeat_poll_exit(microSeconds); - return 0; - } - us = now; + return 0; } - sqLowLevelMFence(); - isPooling = 0; - heartbeat_poll_exit(microSeconds); - aio_flush_pipe(signal_pipe_fd[0]); + if(epollReturn == 0){ + return 0; + } - // We clear signal_pipe_fd because when it arrives here we do not care anymore - // about it, but it may cause a crash if it is set because we do not have - // a handler for it. Another solution could be to just add a handler to signal_pipe_fd - // but for now it does not seems needed. - FD_CLR(signal_pipe_fd[0], &rd); - - for (fd = 0; fd < maxFd; ++fd) { - aioHandler handler; - - //_DO_FLAG_TYPE(); - //_DO(AIO_R, rd) - if (FD_ISSET(fd, &rd)) { - handler = rdHandler[fd]; - FD_CLR(fd, &rdMask); - handler(fd, clientData[fd], AIO_R); - rdHandler[fd]= undefinedHandler; - } - //_DO(AIO_W, wr) - if (FD_ISSET(fd, &wr)) { - handler = wrHandler[fd]; - FD_CLR(fd, &wrMask); - handler(fd, clientData[fd], AIO_W); - wrHandler[fd]= undefinedHandler; - } - //_DO(AIO_X, ex) - if (FD_ISSET(fd, &ex)) { - handler = exHandler[fd]; - FD_CLR(fd, &exMask); - handler(fd, clientData[fd], AIO_X); - exHandler[fd]= undefinedHandler; - } + for(int index = 0; index < epollReturn; index++){ + //Only process the signals that are not from the interrupt pipe + if(incomingEvents[index].data.ptr != NULL){ + triggeredDescriptor = (AioUnixDescriptor*) incomingEvents[index].data.ptr; + + // Clearing the mask, and removing the signaled descriptor from the list, aioHandle will re add it + triggeredDescriptor->mask = 0; + logTrace("Removing events of FD: %d", (int) triggeredDescriptor->fd); + if (epoll_ctl(epollDescriptor, EPOLL_CTL_DEL, triggeredDescriptor->fd, NULL) == -1) { + logError("Error removing FD: %d", (int) triggeredDescriptor->fd); + logErrorFromErrno("epoll_ctl"); + } + + if((incomingEvents[index].events & EPOLLERR) == EPOLLERR){ + withError = AIO_X; + }else{ + withError = 0; + } + + if((incomingEvents[index].events & EPOLLIN) == EPOLLIN){ + if(triggeredDescriptor->readHandlerFn){ + triggeredDescriptor->readHandlerFn(triggeredDescriptor->fd, triggeredDescriptor->clientData, AIO_R | withError); + } + } + if((incomingEvents[index].events & EPOLLOUT) == EPOLLOUT){ + if(triggeredDescriptor->writeHandlerFn){ + triggeredDescriptor->writeHandlerFn(triggeredDescriptor->fd, triggeredDescriptor->clientData, AIO_W | withError); + } + } + } } return 1; @@ -351,37 +334,39 @@ aioInterruptPoll(){ } void -aioEnable(int fd, void *data, int flags) +aioEnable(int fd, void *clientData, int flags) { + AioUnixDescriptor * descriptor; + if (fd < 0) { logWarn("AioEnable(%d): IGNORED - Negative Number", fd); return; } - if (FD_ISSET(fd, &fdMask)) { - logWarn("AioEnable: descriptor %d already enabled", fd); - return; - } - clientData[fd] = data; - rdHandler[fd] = wrHandler[fd] = exHandler[fd] = undefinedHandler; - FD_SET(fd, &fdMask); - FD_CLR(fd, &rdMask); - FD_CLR(fd, &wrMask); - FD_CLR(fd, &exMask); - if (fd >= maxFd) - maxFd = fd + 1; - if (flags & AIO_EXT) { - FD_SET(fd, &xdMask); - /* we should not set NBIO ourselves on external descriptors! */ + + descriptor = AioUnixDescriptor_find(fd); + + if(descriptor == NULL){ + descriptor = malloc(sizeof(AioUnixDescriptor)); + descriptor->readHandlerFn = NULL; + descriptor->writeHandlerFn = NULL; + descriptor->next = descriptorList; + descriptorList = descriptor; + descriptor->mask = 0; } - else { + + descriptor->fd = fd; + descriptor->clientData = clientData; + + logTrace("Enabling FD: %d", (int) descriptor->fd); + + /* we should not set NBIO ourselves on external descriptors! */ + if ((flags & AIO_EXT) != AIO_EXT) { /* * enable non-blocking asynchronous i/o and delivery of SIGIO * to the active process */ int arg; - FD_CLR(fd, &xdMask); - #if defined(O_ASYNC) if (fcntl(fd, F_SETOWN, getpid()) < 0) logErrorFromErrno("fcntl(F_SETOWN, getpid())"); @@ -415,37 +400,96 @@ aioEnable(int fd, void *data, int flags) void aioHandle(int fd, aioHandler handlerFn, int mask) { - if (fd < 0) { - logWarn("aioHandle(%d): IGNORED - Negative FD", fd); + AioUnixDescriptor *descriptor = AioUnixDescriptor_find(fd); + int previousMask; + + if(descriptor == NULL){ + logWarn("Enabling a FD that is not present: %d - IGNORING", fd); return; } -#undef _DO -#define _DO(FLAG, TYPE) \ - if (mask & FLAG) { \ - FD_SET(fd, &TYPE##Mask); \ - TYPE##Handler[fd]= handlerFn; \ - } - _DO_FLAG_TYPE(); + + struct epoll_event ev; + int hasRead = (mask & AIO_R) == AIO_R; + int hasWrite = (mask & AIO_W) == AIO_W; + int hasExceptions = (mask & AIO_X) == AIO_X; + + descriptor->readHandlerFn = hasRead ? handlerFn : NULL; + descriptor->writeHandlerFn = hasWrite ? handlerFn : NULL; + previousMask = descriptor->mask; + descriptor->mask = mask; + + ev.data.ptr = descriptor; + ev.events = 0; + ev.events |= hasRead ? (EPOLLIN | EPOLLRDHUP) : 0; + ev.events |= hasWrite ? (EPOLLOUT | EPOLLRDHUP) : 0; + ev.events |= hasExceptions ? (EPOLLERR | EPOLLRDHUP) : 0; + + logTrace("Handling FD: %d mask: %d events: %d", (int) descriptor->fd, (int) descriptor->mask, (int) ev.events); + + // If we already have it in the epoll, we just update it + if (epoll_ctl(epollDescriptor, previousMask == 0 ? EPOLL_CTL_ADD: EPOLL_CTL_MOD, descriptor->fd, &ev) == -1) { + logError("Error adding FD: %d", (int) descriptor->fd); + logErrorFromErrno("epoll_ctl: add"); + } } /* temporarily suspend asynchronous notification for a descriptor */ void -aioSuspend(int fd, int mask) +aioSuspend(int fd, int maskToSuspend) { - if (fd < 0) { - logWarn("aioSuspend(%d): IGNORED - Negative FD\n", fd); + AioUnixDescriptor *descriptor = AioUnixDescriptor_find(fd); + + if(descriptor == NULL){ + logWarn("Enabling a FD that is not present: %d - IGNORING", fd); return; } + + // If original MASK is 0, we don't register it before. Nothing to suspend + if(descriptor->mask == 0){ + return; + } + + struct epoll_event ev; + int hasRead = (maskToSuspend & AIO_R) == AIO_R; + int hasWrite = (maskToSuspend & AIO_W) == AIO_W; + int hasExceptions = (maskToSuspend & AIO_X) == AIO_X; + + if(hasRead){ + descriptor->readHandlerFn = NULL; + descriptor->mask &= ~AIO_R; + } -#undef _DO -#define _DO(FLAG, TYPE) \ - if (mask & FLAG) { \ - FD_CLR(fd, &TYPE##Mask); \ - TYPE##Handler[fd]= undefinedHandler; \ + if(hasWrite){ + descriptor->writeHandlerFn = NULL; + descriptor->mask &= ~AIO_W; + } + + if(hasExceptions){ + descriptor->mask &= ~AIO_X; + } + + ev.data.ptr = descriptor; + ev.events = 0; + ev.events |= (descriptor->mask & AIO_R) == AIO_R ? (EPOLLIN | EPOLLRDHUP) : 0; + ev.events |= (descriptor->mask & AIO_W) == AIO_W ? (EPOLLOUT | EPOLLRDHUP) : 0; + ev.events |= (descriptor->mask & AIO_X) == AIO_X ? (EPOLLERR | EPOLLRDHUP) : 0; + + logTrace("Suspending FD: %d mask: %d events: %d", (int) descriptor->fd, (int) descriptor->mask, (int) ev.events); + + if(ev.events == 0){ + if (epoll_ctl(epollDescriptor, EPOLL_CTL_DEL, descriptor->fd, NULL) == -1) { + logError("Error removing all suspended FD: %d", (int) descriptor->fd); + logErrorFromErrno("epoll_ctl: del"); + } + return; } - _DO_FLAG_TYPE(); + + if (epoll_ctl(epollDescriptor, EPOLL_CTL_MOD, descriptor->fd, &ev) == -1) { + logError("Error modifying FD: %d", (int) descriptor->fd); + logErrorFromErrno("epoll_ctl: mod"); + } } @@ -454,16 +498,58 @@ aioSuspend(int fd, int mask) void aioDisable(int fd) { - if (fd < 0) { - logWarn( "aioDisable(%d): IGNORED - Negative FD\n", fd); - return; + if (epoll_ctl(epollDescriptor, EPOLL_CTL_DEL, fd, NULL) == -1) { + // The FD maybe does not exist anymore, so we are ignoring this issue + if(errno != EBADF){ + logError("Error removing all suspended FD: %d", fd); + logErrorFromErrno("epoll_ctl: del"); + } } - aioSuspend(fd, AIO_RWX); - FD_CLR(fd, &xdMask); - FD_CLR(fd, &fdMask); - rdHandler[fd] = wrHandler[fd] = exHandler[fd] = 0; - clientData[fd] = 0; - /* keep maxFd accurate (drops to zero if no more sockets) */ - while (maxFd && !FD_ISSET(maxFd - 1, &fdMask)) - --maxFd; + AioUnixDescriptor_remove(fd); } + +AioUnixDescriptor* AioUnixDescriptor_find(int fd){ + AioUnixDescriptor* found; + + found = descriptorList; + while(found != NULL){ + if(found->fd == fd) + return found; + found = found->next; + } + + return NULL; +} + +void AioUnixDescriptor_remove(int fd){ + AioUnixDescriptor* found; + AioUnixDescriptor* prev = NULL; + + found = descriptorList; + + while(found != NULL){ + + if(found->fd == fd){ + if(descriptorList == found){ + descriptorList = found->next; + }else{ + prev->next = found->next; + } + free(found); + return; + } + prev = found; + found = found->next; + } + +} + +void AioUnixDescriptor_removeAll(){ + AioUnixDescriptor* current; + + while(descriptorList != NULL){ + current = descriptorList; + descriptorList = current->next; + free(current); + } +} \ No newline at end of file From 815c02fede6f8ae345ca9831a9980f1a7acb0fb4 Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Wed, 5 Jun 2024 11:17:58 +0200 Subject: [PATCH 2/8] Fixing warnings that are errors in newer versions of clang --- .gitignore | 5 +++- .../plugins/B2DPlugin/src/common/B2DPlugin.c | 8 +++--- .../BitBltPlugin/src/common/BitBltPlugin.c | 4 +-- .../src/common/FileAttributesPlugin.c | 14 +++++----- .../src/common/JPEGReadWriter2Plugin.c | 4 +-- .../LargeIntegers/src/common/LargeIntegers.c | 8 +++--- .../LocalePlugin/src/common/LocalePlugin.c | 4 +-- .../SocketPlugin/src/common/SocketPlugin.c | 8 +++--- .../plugins/SqueakSSL/src/common/SqueakSSL.c | 4 +-- .../src/common/UnixOSProcessPlugin.c | 27 ++++++++++++------- .../vm/include/common/sqVirtualMachine.h | 16 +++++------ .../vm/src/common/sqExternalSemaphores.c | 3 ++- extracted/vm/src/common/sqVirtualMachine.c | 6 ++--- ffiTestLibrary/src/callbacks.c | 2 +- 14 files changed, 64 insertions(+), 49 deletions(-) diff --git a/.gitignore b/.gitignore index 4596fdf409..8959be02f1 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,9 @@ pharo-vm/ ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore +#vscode +.vscode/ + # User-specific files *.rsuser *.suo @@ -367,4 +370,4 @@ healthchecksdb /stack32/generated /stack64/generated -**/.DS_Store \ No newline at end of file +**/.DS_Store diff --git a/extracted/plugins/B2DPlugin/src/common/B2DPlugin.c b/extracted/plugins/B2DPlugin/src/common/B2DPlugin.c index 5261feff4e..843e11b8f1 100644 --- a/extracted/plugins/B2DPlugin/src/common/B2DPlugin.c +++ b/extracted/plugins/B2DPlugin/src/common/B2DPlugin.c @@ -764,7 +764,7 @@ static sqInt (*makePointwithxValueyValue)(sqInt xValue, sqInt yValue); static sqInt (*methodArgumentCount)(void); static sqInt (*nilObject)(void); static sqInt (*pop)(sqInt nItems); -static sqInt (*popthenPush)(sqInt nItems, sqInt oop); +static void (*popthenPush)(sqInt nItems, sqInt oop); static sqInt (*popRemappableOop)(void); static sqInt (*positive32BitIntegerFor)(unsigned int integerValue); static usqInt (*positive32BitValueOf)(sqInt oop); @@ -772,7 +772,7 @@ static sqInt (*primitiveFail)(void); static sqInt (*primitiveFailFor)(sqInt reasonCode); static sqInt (*pushBool)(sqInt trueOrFalse); static sqInt (*pushInteger)(sqInt integerValue); -static sqInt (*pushRemappableOop)(sqInt oop); +static void (*pushRemappableOop)(sqInt oop); static sqInt (*slotSizeOf)(sqInt oop); static sqInt (*stackIntegerValue)(sqInt offset); static sqInt (*stackObjectValue)(sqInt offset); @@ -813,7 +813,7 @@ extern sqInt makePointwithxValueyValue(sqInt xValue, sqInt yValue); extern sqInt methodArgumentCount(void); extern sqInt nilObject(void); extern sqInt pop(sqInt nItems); -extern sqInt popthenPush(sqInt nItems, sqInt oop); +extern void popthenPush(sqInt nItems, sqInt oop); extern sqInt popRemappableOop(void); extern sqInt positive32BitIntegerFor(unsigned int integerValue); extern usqInt positive32BitValueOf(sqInt oop); @@ -821,7 +821,7 @@ extern sqInt primitiveFail(void); extern sqInt primitiveFailFor(sqInt reasonCode); extern sqInt pushBool(sqInt trueOrFalse); extern sqInt pushInteger(sqInt integerValue); -extern sqInt pushRemappableOop(sqInt oop); +extern void pushRemappableOop(sqInt oop); extern sqInt slotSizeOf(sqInt oop); extern sqInt stackIntegerValue(sqInt offset); extern sqInt stackObjectValue(sqInt offset); diff --git a/extracted/plugins/BitBltPlugin/src/common/BitBltPlugin.c b/extracted/plugins/BitBltPlugin/src/common/BitBltPlugin.c index 8c2698e0cc..bd4683f5e9 100644 --- a/extracted/plugins/BitBltPlugin/src/common/BitBltPlugin.c +++ b/extracted/plugins/BitBltPlugin/src/common/BitBltPlugin.c @@ -287,7 +287,7 @@ static sqInt (*methodReturnInteger)(sqInt integer); static sqInt (*methodReturnReceiver)(void); static sqInt (*nilObject)(void); static sqInt (*pop)(sqInt nItems); -static sqInt (*popthenPush)(sqInt nItems, sqInt oop); +static void (*popthenPush)(sqInt nItems, sqInt oop); static sqInt (*positive32BitIntegerFor)(unsigned int integerValue); static usqInt (*positive32BitValueOf)(sqInt oop); static usqLong (*positive64BitValueOf)(sqInt oop); @@ -329,7 +329,7 @@ extern sqInt methodReturnInteger(sqInt integer); extern sqInt methodReturnReceiver(void); extern sqInt nilObject(void); extern sqInt pop(sqInt nItems); -extern sqInt popthenPush(sqInt nItems, sqInt oop); +extern void popthenPush(sqInt nItems, sqInt oop); extern sqInt positive32BitIntegerFor(unsigned int integerValue); extern usqInt positive32BitValueOf(sqInt oop); extern usqLong positive64BitValueOf(sqInt oop); diff --git a/extracted/plugins/FileAttributesPlugin/src/common/FileAttributesPlugin.c b/extracted/plugins/FileAttributesPlugin/src/common/FileAttributesPlugin.c index c7393ee3f7..94936d3dea 100644 --- a/extracted/plugins/FileAttributesPlugin/src/common/FileAttributesPlugin.c +++ b/extracted/plugins/FileAttributesPlugin/src/common/FileAttributesPlugin.c @@ -121,14 +121,14 @@ static sqInt (*isKindOf)(sqInt oop, char *aString); static sqInt (*isBytes)(sqInt oop); static sqInt (*methodReturnValue)(sqInt oop); static sqInt (*nilObject)(void); -static sqInt (*popthenPush)(sqInt nItems, sqInt oop); +static void (*popthenPush)(sqInt nItems, sqInt oop); static sqInt (*popRemappableOop)(void); static sqInt (*positive32BitIntegerFor)(unsigned int integerValue); static sqInt (*primitiveFail)(void); static sqInt (*primitiveFailFor)(sqInt reasonCode); static sqInt (*primitiveFailForOSError)(sqLong osError); static sqInt (*primitiveFailureCode)(void); -static sqInt (*pushRemappableOop)(sqInt oop); +static void (*pushRemappableOop)(sqInt oop); static sqInt (*stSizeOf)(sqInt oop); static sqInt (*stackIntegerValue)(sqInt offset); static sqInt (*stackObjectValue)(sqInt offset); @@ -147,7 +147,7 @@ extern sqInt isKindOf(sqInt oop, char *aString); extern sqInt isBytes(sqInt oop); extern sqInt methodReturnValue(sqInt oop); extern sqInt nilObject(void); -extern sqInt popthenPush(sqInt nItems, sqInt oop); +extern void popthenPush(sqInt nItems, sqInt oop); extern sqInt popRemappableOop(void); extern sqInt positive32BitIntegerFor(unsigned int integerValue); extern sqInt primitiveFail(void); @@ -158,7 +158,7 @@ extern sqInt primitiveFailForOSError(sqLong osError); # define primitiveFailForOSError(osError) 0 #endif extern sqInt primitiveFailureCode(void); -extern sqInt pushRemappableOop(sqInt oop); +extern void pushRemappableOop(sqInt oop); extern sqInt stSizeOf(sqInt oop); extern sqInt stackIntegerValue(sqInt offset); extern sqInt stackObjectValue(sqInt offset); @@ -712,7 +712,8 @@ primitiveLogicalDrives(void) # if defined(_WIN32) mask = GetLogicalDrives(); if (mask != 0) { - return popthenPush(1, positive32BitIntegerFor(mask)); + popthenPush(1, positive32BitIntegerFor(mask)); + return 0; } # endif /* defined(_WIN32) */ primitiveFail(); @@ -813,7 +814,8 @@ primitiveOpendir(void) EXPORT(sqInt) primitivePathMax(void) { - return popthenPush(1, integerObjectOf(FA_PATH_MAX)); + popthenPush(1, integerObjectOf(FA_PATH_MAX)); + return 0; } diff --git a/extracted/plugins/JPEGReadWriter2Plugin/src/common/JPEGReadWriter2Plugin.c b/extracted/plugins/JPEGReadWriter2Plugin/src/common/JPEGReadWriter2Plugin.c index 6c4b570974..bb9e1550ff 100644 --- a/extracted/plugins/JPEGReadWriter2Plugin/src/common/JPEGReadWriter2Plugin.c +++ b/extracted/plugins/JPEGReadWriter2Plugin/src/common/JPEGReadWriter2Plugin.c @@ -72,7 +72,7 @@ static sqInt (*isBytes)(sqInt oop); static sqInt (*isIntegerObject)(sqInt objectPointer); static sqInt (*isWordsOrBytes)(sqInt oop); static sqInt (*pop)(sqInt nItems); -static sqInt (*popthenPush)(sqInt nItems, sqInt oop); +static void (*popthenPush)(sqInt nItems, sqInt oop); static sqInt (*primitiveFail)(void); static sqInt (*primitiveFailFor)(sqInt reasonCode); static sqInt (*stSizeOf)(sqInt oop); @@ -101,7 +101,7 @@ extern sqInt isIntegerObject(sqInt objectPointer); #endif extern sqInt isWordsOrBytes(sqInt oop); extern sqInt pop(sqInt nItems); -extern sqInt popthenPush(sqInt nItems, sqInt oop); +extern void popthenPush(sqInt nItems, sqInt oop); extern sqInt primitiveFail(void); extern sqInt primitiveFailFor(sqInt reasonCode); extern sqInt stSizeOf(sqInt oop); diff --git a/extracted/plugins/LargeIntegers/src/common/LargeIntegers.c b/extracted/plugins/LargeIntegers/src/common/LargeIntegers.c index dd427ccc9b..5bac5ba9af 100644 --- a/extracted/plugins/LargeIntegers/src/common/LargeIntegers.c +++ b/extracted/plugins/LargeIntegers/src/common/LargeIntegers.c @@ -117,12 +117,12 @@ static sqInt (*integerObjectOf)(sqInt value); static sqInt (*integerValueOf)(sqInt oop); static sqInt (*isBooleanObject)(sqInt oop); static sqInt (*isIntegerObject)(sqInt objectPointer); -static sqInt (*popthenPush)(sqInt nItems, sqInt oop); +static void (*popthenPush)(sqInt nItems, sqInt oop); static sqInt (*popRemappableOop)(void); static usqInt (*positive32BitValueOf)(sqInt oop); static sqInt (*primitiveFail)(void); static sqInt (*primitiveFailFor)(sqInt reasonCode); -static sqInt (*pushRemappableOop)(sqInt oop); +static void (*pushRemappableOop)(sqInt oop); static sqInt (*slotSizeOf)(sqInt oop); static sqInt (*stObjectatput)(sqInt array, sqInt index, sqInt value); static sqInt (*stackIntegerValue)(sqInt offset); @@ -150,12 +150,12 @@ extern sqInt isBooleanObject(sqInt oop); #if !defined(isIntegerObject) extern sqInt isIntegerObject(sqInt objectPointer); #endif -extern sqInt popthenPush(sqInt nItems, sqInt oop); +extern void popthenPush(sqInt nItems, sqInt oop); extern sqInt popRemappableOop(void); extern usqInt positive32BitValueOf(sqInt oop); extern sqInt primitiveFail(void); extern sqInt primitiveFailFor(sqInt reasonCode); -extern sqInt pushRemappableOop(sqInt oop); +extern void pushRemappableOop(sqInt oop); extern sqInt slotSizeOf(sqInt oop); extern sqInt stObjectatput(sqInt array, sqInt index, sqInt value); extern sqInt stackIntegerValue(sqInt offset); diff --git a/extracted/plugins/LocalePlugin/src/common/LocalePlugin.c b/extracted/plugins/LocalePlugin/src/common/LocalePlugin.c index 96b5f33307..6a697c2d77 100644 --- a/extracted/plugins/LocalePlugin/src/common/LocalePlugin.c +++ b/extracted/plugins/LocalePlugin/src/common/LocalePlugin.c @@ -63,7 +63,7 @@ static sqInt (*falseObject)(void); static void * (*firstIndexableField)(sqInt oop); static sqInt (*instantiateClassindexableSize)(sqInt classPointer, sqInt size); static sqInt (*integerObjectOf)(sqInt value); -static sqInt (*popthenPush)(sqInt nItems, sqInt oop); +static void (*popthenPush)(sqInt nItems, sqInt oop); static sqInt (*trueObject)(void); #else /* !defined(SQUEAK_BUILTIN_PLUGIN) */ extern sqInt classString(void); @@ -72,7 +72,7 @@ extern sqInt falseObject(void); extern void * firstIndexableField(sqInt oop); extern sqInt instantiateClassindexableSize(sqInt classPointer, sqInt size); extern sqInt integerObjectOf(sqInt value); -extern sqInt popthenPush(sqInt nItems, sqInt oop); +extern void popthenPush(sqInt nItems, sqInt oop); extern sqInt trueObject(void); extern #endif diff --git a/extracted/plugins/SocketPlugin/src/common/SocketPlugin.c b/extracted/plugins/SocketPlugin/src/common/SocketPlugin.c index f8ed75a128..883c1a8b89 100644 --- a/extracted/plugins/SocketPlugin/src/common/SocketPlugin.c +++ b/extracted/plugins/SocketPlugin/src/common/SocketPlugin.c @@ -130,11 +130,11 @@ static sqInt (*isWords)(sqInt oop); static sqInt (*isWordsOrBytes)(sqInt oop); static sqInt (*methodArgumentCount)(void); static sqInt (*pop)(sqInt nItems); -static sqInt (*popthenPush)(sqInt nItems, sqInt oop); +static void (*popthenPush)(sqInt nItems, sqInt oop); static sqInt (*popRemappableOop)(void); static sqInt (*primitiveFail)(void); static sqInt (*primitiveFailFor)(sqInt reasonCode); -static sqInt (*pushRemappableOop)(sqInt oop); +static void (*pushRemappableOop)(sqInt oop); static sqInt (*slotSizeOf)(sqInt oop); static sqInt (*stackIntegerValue)(sqInt offset); static sqInt (*stackValue)(sqInt offset); @@ -160,11 +160,11 @@ extern sqInt isWords(sqInt oop); extern sqInt isWordsOrBytes(sqInt oop); extern sqInt methodArgumentCount(void); extern sqInt pop(sqInt nItems); -extern sqInt popthenPush(sqInt nItems, sqInt oop); +extern void popthenPush(sqInt nItems, sqInt oop); extern sqInt popRemappableOop(void); extern sqInt primitiveFail(void); extern sqInt primitiveFailFor(sqInt reasonCode); -extern sqInt pushRemappableOop(sqInt oop); +extern void pushRemappableOop(sqInt oop); extern sqInt slotSizeOf(sqInt oop); extern sqInt stackIntegerValue(sqInt offset); extern sqInt stackValue(sqInt offset); diff --git a/extracted/plugins/SqueakSSL/src/common/SqueakSSL.c b/extracted/plugins/SqueakSSL/src/common/SqueakSSL.c index ddb2bc024e..04dde31c21 100644 --- a/extracted/plugins/SqueakSSL/src/common/SqueakSSL.c +++ b/extracted/plugins/SqueakSSL/src/common/SqueakSSL.c @@ -61,7 +61,7 @@ static sqInt (*isBytes)(sqInt oop); static sqInt (*methodArgumentCount)(void); static sqInt (*nilObject)(void); static sqInt (*pop)(sqInt nItems); -static sqInt (*popthenPush)(sqInt nItems, sqInt oop); +static void (*popthenPush)(sqInt nItems, sqInt oop); static sqInt (*primitiveFail)(void); static sqInt (*pushInteger)(sqInt integerValue); static sqInt (*signed32BitIntegerFor)(sqInt integerValue); @@ -78,7 +78,7 @@ extern sqInt isBytes(sqInt oop); extern sqInt methodArgumentCount(void); extern sqInt nilObject(void); extern sqInt pop(sqInt nItems); -extern sqInt popthenPush(sqInt nItems, sqInt oop); +extern void popthenPush(sqInt nItems, sqInt oop); extern sqInt primitiveFail(void); extern sqInt pushInteger(sqInt integerValue); extern sqInt signed32BitIntegerFor(sqInt integerValue); diff --git a/extracted/plugins/UnixOSProcessPlugin/src/common/UnixOSProcessPlugin.c b/extracted/plugins/UnixOSProcessPlugin/src/common/UnixOSProcessPlugin.c index 2e22dd9d65..788e9a1788 100644 --- a/extracted/plugins/UnixOSProcessPlugin/src/common/UnixOSProcessPlugin.c +++ b/extracted/plugins/UnixOSProcessPlugin/src/common/UnixOSProcessPlugin.c @@ -277,13 +277,13 @@ static sqInt (*methodArgumentCount)(void); static sqInt (*methodReturnValue)(sqInt oop); static sqInt (*nilObject)(void); static sqInt (*pop)(sqInt nItems); -static sqInt (*popthenPush)(sqInt nItems, sqInt oop); +static void (*popthenPush)(sqInt nItems, sqInt oop); static sqInt (*popRemappableOop)(void); static sqInt (*primitiveFail)(void); static sqInt (*primitiveFailFor)(sqInt reasonCode); -static (*push)(sqInt object); +static void (*push)(sqInt object); static sqInt (*pushInteger)(sqInt integerValue); -static sqInt (*pushRemappableOop)(sqInt oop); +static void (*pushRemappableOop)(sqInt oop); static sqInt (*signalSemaphoreWithIndex)(sqInt semaIndex); static sqInt (*sizeOfSTArrayFromCPrimitive)(void *cPtr); static sqInt (*stObjectatput)(sqInt array, sqInt index, sqInt value); @@ -315,13 +315,13 @@ extern sqInt methodArgumentCount(void); extern sqInt methodReturnValue(sqInt oop); extern sqInt nilObject(void); extern sqInt pop(sqInt nItems); -extern sqInt popthenPush(sqInt nItems, sqInt oop); +extern void popthenPush(sqInt nItems, sqInt oop); extern sqInt popRemappableOop(void); extern sqInt primitiveFail(void); extern sqInt primitiveFailFor(sqInt reasonCode); -extern sqInt push(sqInt object); +extern void push(sqInt object); extern sqInt pushInteger(sqInt integerValue); -extern sqInt pushRemappableOop(sqInt oop); +extern void pushRemappableOop(sqInt oop); extern sqInt signalSemaphoreWithIndex(sqInt semaIndex); extern sqInt sizeOfSTArrayFromCPrimitive(void *cPtr); extern sqInt stObjectatput(sqInt array, sqInt index, sqInt value); @@ -1187,7 +1187,9 @@ getStdHandle(sqInt n) return primitiveFailFor(PrimErrNoMemory); } memcpy(firstIndexableField(fileOop), &fileRecords[n], sizeof(SQFile)); - return popthenPush(1, fileOop); + popthenPush(1, fileOop); + + return fileOop; } /* OSProcessPlugin>>#getThisSessionIdentifier */ @@ -4287,7 +4289,6 @@ reapChildProcess(int sigNum) } } - /* Signal sigNum has been caught by a thread other than the pthread in which the interpreter is executing. Rather than handling it in this thread, resend it to the interpreter thread. */ @@ -4431,6 +4432,14 @@ setInterpreter(struct VirtualMachine *anInterpreter) return ok; } +# if defined(SA_NOCLDSTOP) +/* This wrapper is used to handle the new signature of the function */ + +static void +reapChildProcessWrapper(int sigNum, struct __siginfo * sigInfo, void * userData){ + reapChildProcess(sigNum); +} +# endif /* Set the SIGCHLD signal handler in the virtual machine. */ @@ -4442,7 +4451,7 @@ setSigChldHandler(void) # if defined(SA_NOCLDSTOP) - sigchldHandlerAction.sa_sigaction = reapChildProcess; + sigchldHandlerAction.sa_sigaction = reapChildProcessWrapper; sigchldHandlerAction.sa_flags = SA_NODEFER | SA_NOCLDSTOP; if (needSigaltstack()) { sigchldHandlerAction.sa_flags |= SA_ONSTACK; diff --git a/extracted/vm/include/common/sqVirtualMachine.h b/extracted/vm/include/common/sqVirtualMachine.h index 214ce74f34..08811cf45a 100644 --- a/extracted/vm/include/common/sqVirtualMachine.h +++ b/extracted/vm/include/common/sqVirtualMachine.h @@ -30,6 +30,8 @@ #include "sqMemoryAccess.h" +#include "pharovm/semaphores/pSemaphore.h" + #if VM_PROXY_MINOR > 8 # define PrimNoErr 0 # define PrimErrGenericFailure 1 @@ -47,8 +49,6 @@ # define PrimErrNamedInternal 13 # define PrimErrObjectMayMove 14 -/* VMCallbackContext opaque type avoids all including setjmp.h & vmCallback.h */ -typedef struct _VMCallbackContext *vmccp; #endif typedef sqInt (*CompilerHook)(); @@ -62,7 +62,7 @@ typedef struct VirtualMachine { /* InterpreterProxy methodsFor: 'stack access' */ sqInt (*pop)(sqInt nItems); - sqInt (*popthenPush)(sqInt nItems, sqInt oop); + void (*popthenPush)(sqInt nItems, sqInt oop); void (*push)(sqInt object); sqInt (*pushBool)(sqInt trueOrFalse); void (*pushFloat)(double f); @@ -155,7 +155,7 @@ typedef struct VirtualMachine { sqInt (*instantiateClassindexableSize)(sqInt classPointer, sqInt size); sqInt (*makePointwithxValueyValue)(sqInt xValue, sqInt yValue); sqInt (*popRemappableOop)(void); - sqInt (*pushRemappableOop)(sqInt oop); + void (*pushRemappableOop)(sqInt oop); /* InterpreterProxy methodsFor: 'other' */ @@ -312,7 +312,7 @@ typedef struct VirtualMachine { #if VM_PROXY_MINOR > 12 /* Spur */ sqInt (*isImmediate)(sqInt objOop); - sqInt (*characterObjectOf)(int charCode); + sqInt (*characterObjectOf)(sqInt charCode); sqInt (*characterValueOf)(sqInt objOop); sqInt (*isCharacterObject)(sqInt objOop); sqInt (*isCharacterValue)(int charCode); @@ -331,11 +331,11 @@ typedef struct VirtualMachine { sqInt (*isPositiveMachineIntegerObject)(sqInt); #endif - sqInt (*ptEnterInterpreterFromCallback)(vmccp); - sqInt (*ptExitInterpreterToCallback)(vmccp); + sqInt (*ptEnterInterpreterFromCallback)(void *); + sqInt (*ptExitInterpreterToCallback)(void *); sqInt (*isNonImmediate)(sqInt oop); - sqInt (*platformSemaphoreNew)(int initialValue); + Semaphore* (*platformSemaphoreNew)(int initialValue); sqInt (*scheduleInMainThread)(sqInt (*closure)()); diff --git a/extracted/vm/src/common/sqExternalSemaphores.c b/extracted/vm/src/common/sqExternalSemaphores.c index 275b1ce9fd..5abef48a09 100644 --- a/extracted/vm/src/common/sqExternalSemaphores.c +++ b/extracted/vm/src/common/sqExternalSemaphores.c @@ -240,6 +240,8 @@ doSignalExternalSemaphores(sqInt externalSemaphoreTableSize) } sqLowLevelMFence(); + requestMutex->signal(requestMutex); + /* doing this here saves a bounds check in doSignalSemaphoreWithIndex */ if (highTide >= externalSemaphoreTableSize) highTide = externalSemaphoreTableSize - 1; @@ -251,7 +253,6 @@ doSignalExternalSemaphores(sqInt externalSemaphoreTableSize) signalled = 1; } - requestMutex->signal(requestMutex); #if !defined(_WIN32) sigprocmask(SIG_UNBLOCK, &blockedSignalSet, NULL); #endif diff --git a/extracted/vm/src/common/sqVirtualMachine.c b/extracted/vm/src/common/sqVirtualMachine.c index 850fcb9d9f..29e4ead2de 100644 --- a/extracted/vm/src/common/sqVirtualMachine.c +++ b/extracted/vm/src/common/sqVirtualMachine.c @@ -11,7 +11,7 @@ /* InterpreterProxy methodsFor: 'stack access' */ sqInt pop(sqInt nItems); -sqInt popthenPush(sqInt nItems, sqInt oop); +void popthenPush(sqInt nItems, sqInt oop); void push(sqInt object); sqInt pushBool(sqInt trueOrFalse); void pushFloat(double f); @@ -127,7 +127,7 @@ sqInt clone(sqInt oop); sqInt instantiateClassindexableSize(sqInt classPointer, sqInt size); sqInt makePointwithxValueyValue(sqInt xValue, sqInt yValue); sqInt popRemappableOop(void); -sqInt pushRemappableOop(sqInt oop); +void pushRemappableOop(sqInt oop); /* InterpreterProxy methodsFor: 'other' */ @@ -168,7 +168,7 @@ sqInt signalNoResume(sqInt); sqInt isImmediate(sqInt oop); sqInt isCharacterObject(sqInt oop); sqInt isCharacterValue(int charCode); -sqInt characterObjectOf(int charCode); +sqInt characterObjectOf(sqInt charCode); sqInt characterValueOf(sqInt oop); sqInt isPinned(sqInt objOop); sqInt pinObject(sqInt objOop); diff --git a/ffiTestLibrary/src/callbacks.c b/ffiTestLibrary/src/callbacks.c index 5773b9f850..2baa45ca9e 100644 --- a/ffiTestLibrary/src/callbacks.c +++ b/ffiTestLibrary/src/callbacks.c @@ -34,7 +34,7 @@ EXPORT(int) reentringCallback(SIMPLE_CALLBACK fun, int base){ static int value = 0; #if FEATURE_THREADED_FFI -void otherThread(void* aFunction){ +void* otherThread(void* aFunction){ SIMPLE_CALLBACK f = (SIMPLE_CALLBACK) aFunction; #ifdef _WIN32 From 5df45a8fa6e1015d6d121ac2f8e41364a2f85a94 Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Thu, 6 Jun 2024 11:55:14 +0200 Subject: [PATCH 3/8] Improving the EPoll implementation: creating the descriptor each time and removing select from socket writable --- .../src/common/SocketPluginImpl.c | 8 +- extracted/vm/include/common/sqaio.h | 2 + extracted/vm/src/unix/aio.c | 180 ++++++++++-------- 3 files changed, 104 insertions(+), 86 deletions(-) diff --git a/extracted/plugins/SocketPlugin/src/common/SocketPluginImpl.c b/extracted/plugins/SocketPlugin/src/common/SocketPluginImpl.c index 9b8bc2703e..bbcdf27eac 100644 --- a/extracted/plugins/SocketPlugin/src/common/SocketPluginImpl.c +++ b/extracted/plugins/SocketPlugin/src/common/SocketPluginImpl.c @@ -446,13 +446,7 @@ static int socketReadable(int s, int type) static int socketWritable(int s) { - struct timeval tv= { 0, 0 }; - fd_set fds; - - FD_ZERO(&fds); - FD_SET(s, &fds); - - return select(s+1, 0, &fds, 0, &tv) > 0; + return aioFDWritable(s); } /* answer the error condition on the given socket */ diff --git a/extracted/vm/include/common/sqaio.h b/extracted/vm/include/common/sqaio.h index 0f1eecd573..94d813b74c 100644 --- a/extracted/vm/include/common/sqaio.h +++ b/extracted/vm/include/common/sqaio.h @@ -101,6 +101,8 @@ EXPORT(void) aioInterruptPoll(); */ EXPORT(void) aioWaitIfInPoll(); +EXPORT(int) aioFDWritable(int s); + /* debugging stuff. */ #ifdef AIO_DEBUG diff --git a/extracted/vm/src/unix/aio.c b/extracted/vm/src/unix/aio.c index 1b3affc5f1..128061f273 100644 --- a/extracted/vm/src/unix/aio.c +++ b/extracted/vm/src/unix/aio.c @@ -80,11 +80,6 @@ AioUnixDescriptor* AioUnixDescriptor_find(int fd); void AioUnixDescriptor_remove(int fd); void AioUnixDescriptor_removeAll(); -/* - * This is descriptor epoll uses in the poll of the events. - */ -int epollDescriptor = -1; - /* * This is important, the AIO poll should only do a long pause if there is no pending signals for semaphores. * Check ExternalSemaphores to understand this function. @@ -114,7 +109,6 @@ void aioInit(void) { int arg; - struct epoll_event ev; interruptFIFOMutex = platform_semaphore_new(1); @@ -133,20 +127,6 @@ aioInit(void) if (fcntl(signal_pipe_fd[1], F_SETFL, arg | O_NONBLOCK | O_ASYNC | O_APPEND) < 0) logErrorFromErrno("fcntl(F_SETFL, O_ASYNC)"); - epollDescriptor = epoll_create1(0); - if (epollDescriptor == -1) { - logErrorFromErrno("epoll_create1"); - exit(-1); - } - - ev.events = EPOLLIN; - ev.data.ptr = NULL; - - if (epoll_ctl(epollDescriptor, EPOLL_CTL_ADD, signal_pipe_fd[0], &ev) == -1) { - logErrorFromErrno("epoll_ctl: signal_pipe_fd[0]"); - exit(-1); - } - signal(SIGIO, sigIOHandler); } @@ -154,12 +134,7 @@ aioInit(void) void aioFini(void) -{ - if(epollDescriptor != -1){ - close(epollDescriptor); - epollDescriptor = -1; - } - +{ AioUnixDescriptor_removeAll(); signal(SIGIO, SIG_DFL); } @@ -234,6 +209,96 @@ aioPoll(long microSeconds){ return aio_handle_events(timeout); } +static int addFDToEPoll(int epollDescriptor, int fd, int events, void* userData){ + struct epoll_event ev; + ev.events = events; + ev.data.ptr = userData; + + if (epoll_ctl(epollDescriptor, EPOLL_CTL_ADD, fd, &ev) == -1) { + logError("Error adding FD %d to Epoll", fd); + logErrorFromErrno("epoll_ctl"); + return -1; + } + + return 0; +} + +static int fillEPollDescriptor(){ + + int epollDescriptor = epoll_create1(0); + + if (epollDescriptor == -1) { + logErrorFromErrno("epoll_create1"); + return -1; + } + + if(addFDToEPoll(epollDescriptor, signal_pipe_fd[0], EPOLLIN, NULL) == -1){ + logError("Error adding Pipe FD"); + + if(epollDescriptor != -1){ + close(epollDescriptor); + epollDescriptor = -1; + } + return -1; + } + + AioUnixDescriptor* descriptor = descriptorList; + + while(descriptor){ + int hasRead = (descriptor->mask & AIO_R) == AIO_R; + int hasWrite = (descriptor->mask & AIO_W) == AIO_W; + int hasExceptions = (descriptor->mask & AIO_X) == AIO_X; + + int events = 0; + events |= hasRead ? (EPOLLIN | EPOLLRDHUP) : 0; + events |= hasWrite ? (EPOLLOUT | EPOLLRDHUP) : 0; + events |= hasExceptions ? (EPOLLERR | EPOLLRDHUP) : 0; + + if(addFDToEPoll(epollDescriptor, descriptor->fd, events, descriptor) == -1){ + if(epollDescriptor != -1){ + close(epollDescriptor); + epollDescriptor = -1; + } + + return -1; + } + + descriptor = descriptor->next; + } + + return epollDescriptor; +} + +EXPORT(int) aioFDWritable(int fd){ + + int epollDescriptor; + int isWritable = 0; + int epollReturn = 0; + struct epoll_event incomingEvents[1]; + + + epollDescriptor = epoll_create1(0); + if (epollDescriptor == -1) { + logErrorFromErrno("epoll_create1"); + return isWritable; + } + + if(addFDToEPoll(epollDescriptor, fd, EPOLLOUT, NULL) == -1){ + if(epollDescriptor != -1){ + close(epollDescriptor); + } + return isWritable; + } + + epollReturn = epoll_wait(epollDescriptor, incomingEvents, 1, 0); + + if(epollDescriptor != -1){ + close(epollDescriptor); + } + + return (incomingEvents[0].events & EPOLLOUT) == EPOLLOUT; +} + static int aio_handle_events(long microSecondsTimeout){ @@ -242,6 +307,8 @@ aio_handle_events(long microSecondsTimeout){ int withError = 0; AioUnixDescriptor* triggeredDescriptor; + int epollDescriptor = -1; + long milliSecondsTimeout = microSecondsTimeout / 1000; //I notify the heartbeat of a pause @@ -250,8 +317,15 @@ aio_handle_events(long microSecondsTimeout){ sqLowLevelMFence(); isPooling = 1; + epollDescriptor = fillEPollDescriptor(); + epollReturn = epoll_wait(epollDescriptor, incomingEvents, INCOMING_EVENTS_SIZE, milliSecondsTimeout); + if(epollDescriptor != -1){ + close(epollDescriptor); + epollDescriptor = -1; + } + sqLowLevelMFence(); isPooling = 0; @@ -279,13 +353,8 @@ aio_handle_events(long microSecondsTimeout){ if(incomingEvents[index].data.ptr != NULL){ triggeredDescriptor = (AioUnixDescriptor*) incomingEvents[index].data.ptr; - // Clearing the mask, and removing the signaled descriptor from the list, aioHandle will re add it + // Clearing the mask aioHandle will re add it triggeredDescriptor->mask = 0; - logTrace("Removing events of FD: %d", (int) triggeredDescriptor->fd); - if (epoll_ctl(epollDescriptor, EPOLL_CTL_DEL, triggeredDescriptor->fd, NULL) == -1) { - logError("Error removing FD: %d", (int) triggeredDescriptor->fd); - logErrorFromErrno("epoll_ctl"); - } if((incomingEvents[index].events & EPOLLERR) == EPOLLERR){ withError = AIO_X; @@ -401,36 +470,18 @@ void aioHandle(int fd, aioHandler handlerFn, int mask) { AioUnixDescriptor *descriptor = AioUnixDescriptor_find(fd); - int previousMask; if(descriptor == NULL){ logWarn("Enabling a FD that is not present: %d - IGNORING", fd); return; } - struct epoll_event ev; int hasRead = (mask & AIO_R) == AIO_R; int hasWrite = (mask & AIO_W) == AIO_W; - int hasExceptions = (mask & AIO_X) == AIO_X; descriptor->readHandlerFn = hasRead ? handlerFn : NULL; descriptor->writeHandlerFn = hasWrite ? handlerFn : NULL; - previousMask = descriptor->mask; descriptor->mask = mask; - - ev.data.ptr = descriptor; - ev.events = 0; - ev.events |= hasRead ? (EPOLLIN | EPOLLRDHUP) : 0; - ev.events |= hasWrite ? (EPOLLOUT | EPOLLRDHUP) : 0; - ev.events |= hasExceptions ? (EPOLLERR | EPOLLRDHUP) : 0; - - logTrace("Handling FD: %d mask: %d events: %d", (int) descriptor->fd, (int) descriptor->mask, (int) ev.events); - - // If we already have it in the epoll, we just update it - if (epoll_ctl(epollDescriptor, previousMask == 0 ? EPOLL_CTL_ADD: EPOLL_CTL_MOD, descriptor->fd, &ev) == -1) { - logError("Error adding FD: %d", (int) descriptor->fd); - logErrorFromErrno("epoll_ctl: add"); - } } @@ -451,7 +502,6 @@ aioSuspend(int fd, int maskToSuspend) return; } - struct epoll_event ev; int hasRead = (maskToSuspend & AIO_R) == AIO_R; int hasWrite = (maskToSuspend & AIO_W) == AIO_W; int hasExceptions = (maskToSuspend & AIO_X) == AIO_X; @@ -469,27 +519,6 @@ aioSuspend(int fd, int maskToSuspend) if(hasExceptions){ descriptor->mask &= ~AIO_X; } - - ev.data.ptr = descriptor; - ev.events = 0; - ev.events |= (descriptor->mask & AIO_R) == AIO_R ? (EPOLLIN | EPOLLRDHUP) : 0; - ev.events |= (descriptor->mask & AIO_W) == AIO_W ? (EPOLLOUT | EPOLLRDHUP) : 0; - ev.events |= (descriptor->mask & AIO_X) == AIO_X ? (EPOLLERR | EPOLLRDHUP) : 0; - - logTrace("Suspending FD: %d mask: %d events: %d", (int) descriptor->fd, (int) descriptor->mask, (int) ev.events); - - if(ev.events == 0){ - if (epoll_ctl(epollDescriptor, EPOLL_CTL_DEL, descriptor->fd, NULL) == -1) { - logError("Error removing all suspended FD: %d", (int) descriptor->fd); - logErrorFromErrno("epoll_ctl: del"); - } - return; - } - - if (epoll_ctl(epollDescriptor, EPOLL_CTL_MOD, descriptor->fd, &ev) == -1) { - logError("Error modifying FD: %d", (int) descriptor->fd); - logErrorFromErrno("epoll_ctl: mod"); - } } @@ -498,13 +527,6 @@ aioSuspend(int fd, int maskToSuspend) void aioDisable(int fd) { - if (epoll_ctl(epollDescriptor, EPOLL_CTL_DEL, fd, NULL) == -1) { - // The FD maybe does not exist anymore, so we are ignoring this issue - if(errno != EBADF){ - logError("Error removing all suspended FD: %d", fd); - logErrorFromErrno("epoll_ctl: del"); - } - } AioUnixDescriptor_remove(fd); } From 3a073ca0871efb614c95eae98e7dd7fa555d8033 Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Thu, 6 Jun 2024 13:48:26 +0200 Subject: [PATCH 4/8] Adding new implementation of socketWritable for OSX and Windows --- extracted/vm/src/osx/aioOSX.c | 24 ++++++++++++++++++++++++ extracted/vm/src/win/aioWin.c | 19 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/extracted/vm/src/osx/aioOSX.c b/extracted/vm/src/osx/aioOSX.c index 3961a8b1e3..8a7759ae39 100644 --- a/extracted/vm/src/osx/aioOSX.c +++ b/extracted/vm/src/osx/aioOSX.c @@ -445,3 +445,27 @@ void AioOSXDescriptor_remove(int fd){ } } + +EXPORT(int) aioFDWritable(int fd){ + struct kevent incomingEvents[1]; + int keventReturn; + struct timespec timeout; + int kFD; + struct kevent change; + + if((kFD = kqueue()) < 0) { + logErrorFromErrno("kqueue"); + return 0; + } + + EV_SET(&change, fd, EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, NULL); + + timeout.tv_nsec = 0; + timeout.tv_sec = 0; + keventReturn = kevent(kFD, &change, 1, incomingEvents, 1, &timeout); + + if(kFD != -1) + close(kFD); + + return keventReturn == 1; +} \ No newline at end of file diff --git a/extracted/vm/src/win/aioWin.c b/extracted/vm/src/win/aioWin.c index 28256e7ddd..4f4a3689ca 100644 --- a/extracted/vm/src/win/aioWin.c +++ b/extracted/vm/src/win/aioWin.c @@ -532,3 +532,22 @@ EXPORT(void) aioInterruptPoll(){ SetEvent(interruptEvent); } +EXPORT(int) aioFDWritable(int fd){ + HANDLE event; + DWORD returnValue; + + event = WSACreateEvent(); + + if(event == WSA_INVALID_EVENT){ + int lastError = WSAGetLastError(); + logError("Error WSACreateEvent READ: %ld", lastError); + return 0; + } + + WSAEventSelect(fd, hEvent[0], FD_WRITE); + + returnValue = WaitForSingleObject(event, 0); + WSACloseEvent(event); + + return returnValue == WAIT_OBJECT_0; +} \ No newline at end of file From 9df3ae865bab759155027dd3e2617206468fe527 Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Thu, 6 Jun 2024 14:35:15 +0200 Subject: [PATCH 5/8] Fixing typo --- extracted/vm/src/win/aioWin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extracted/vm/src/win/aioWin.c b/extracted/vm/src/win/aioWin.c index 4f4a3689ca..cc11634dba 100644 --- a/extracted/vm/src/win/aioWin.c +++ b/extracted/vm/src/win/aioWin.c @@ -544,7 +544,7 @@ EXPORT(int) aioFDWritable(int fd){ return 0; } - WSAEventSelect(fd, hEvent[0], FD_WRITE); + WSAEventSelect(fd, event, FD_WRITE); returnValue = WaitForSingleObject(event, 0); WSACloseEvent(event); From 64424af111cac3415277dbd7567b19f1438dc616 Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Fri, 7 Jun 2024 13:22:20 +0200 Subject: [PATCH 6/8] In Windows, we need to do the call and handle the WSAEWOULDBLOCK error. So we assume, we can always write --- extracted/vm/src/win/aioWin.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/extracted/vm/src/win/aioWin.c b/extracted/vm/src/win/aioWin.c index cc11634dba..7e4c0f42d2 100644 --- a/extracted/vm/src/win/aioWin.c +++ b/extracted/vm/src/win/aioWin.c @@ -533,21 +533,10 @@ EXPORT(void) aioInterruptPoll(){ } EXPORT(int) aioFDWritable(int fd){ - HANDLE event; - DWORD returnValue; - - event = WSACreateEvent(); - - if(event == WSA_INVALID_EVENT){ - int lastError = WSAGetLastError(); - logError("Error WSACreateEvent READ: %ld", lastError); - return 0; - } - - WSAEventSelect(fd, event, FD_WRITE); - returnValue = WaitForSingleObject(event, 0); - WSACloseEvent(event); - - return returnValue == WAIT_OBJECT_0; +/* + In Windows, we should assume the socket are always writable and then handle the issue with WSAEWOULDBLOCK error. + Once the write fails, it is registered and the socket will be written when it will not block. +*/ + return 1; } \ No newline at end of file From dfce7ded11c43f445f1baf8b6ae3f772aa64ea8d Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Fri, 7 Jun 2024 14:08:36 +0200 Subject: [PATCH 7/8] We can always assume we are not going to block and use the events mechanisms --- extracted/vm/src/osx/aioOSX.c | 23 ++--------------------- extracted/vm/src/unix/aio.c | 29 ++--------------------------- 2 files changed, 4 insertions(+), 48 deletions(-) diff --git a/extracted/vm/src/osx/aioOSX.c b/extracted/vm/src/osx/aioOSX.c index 8a7759ae39..de9316f6a2 100644 --- a/extracted/vm/src/osx/aioOSX.c +++ b/extracted/vm/src/osx/aioOSX.c @@ -447,25 +447,6 @@ void AioOSXDescriptor_remove(int fd){ } EXPORT(int) aioFDWritable(int fd){ - struct kevent incomingEvents[1]; - int keventReturn; - struct timespec timeout; - int kFD; - struct kevent change; - - if((kFD = kqueue()) < 0) { - logErrorFromErrno("kqueue"); - return 0; - } - - EV_SET(&change, fd, EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, NULL); - - timeout.tv_nsec = 0; - timeout.tv_sec = 0; - keventReturn = kevent(kFD, &change, 1, incomingEvents, 1, &timeout); - - if(kFD != -1) - close(kFD); - - return keventReturn == 1; + // We can assume we can always write. If there is a problem the send/sendto will return EAWOULDBLOCK and we will use the event mechanism. + return 1; } \ No newline at end of file diff --git a/extracted/vm/src/unix/aio.c b/extracted/vm/src/unix/aio.c index 128061f273..0374df3179 100644 --- a/extracted/vm/src/unix/aio.c +++ b/extracted/vm/src/unix/aio.c @@ -270,33 +270,8 @@ static int fillEPollDescriptor(){ } EXPORT(int) aioFDWritable(int fd){ - - int epollDescriptor; - int isWritable = 0; - int epollReturn = 0; - struct epoll_event incomingEvents[1]; - - - epollDescriptor = epoll_create1(0); - if (epollDescriptor == -1) { - logErrorFromErrno("epoll_create1"); - return isWritable; - } - - if(addFDToEPoll(epollDescriptor, fd, EPOLLOUT, NULL) == -1){ - if(epollDescriptor != -1){ - close(epollDescriptor); - } - return isWritable; - } - - epollReturn = epoll_wait(epollDescriptor, incomingEvents, 1, 0); - - if(epollDescriptor != -1){ - close(epollDescriptor); - } - - return (incomingEvents[0].events & EPOLLOUT) == EPOLLOUT; + // We can assume we can always write. If there is a problem the send/sendto will return EAWOULDBLOCK and we will use the event mechanism. + return 1; } static int From 34319c6f041f80914cac5dd2ba0c9725964b9234 Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Fri, 7 Jun 2024 15:06:45 +0200 Subject: [PATCH 8/8] Removing socketWritable check as we can always use the event system to handle the would block error in send/sendto --- .../src/common/SocketPluginImpl.c | 19 +++++-------------- extracted/vm/include/common/sqaio.h | 3 --- extracted/vm/src/osx/aioOSX.c | 5 ----- extracted/vm/src/unix/aio.c | 5 ----- extracted/vm/src/win/aioWin.c | 9 --------- 5 files changed, 5 insertions(+), 36 deletions(-) diff --git a/extracted/plugins/SocketPlugin/src/common/SocketPluginImpl.c b/extracted/plugins/SocketPlugin/src/common/SocketPluginImpl.c index bbcdf27eac..95429131b3 100644 --- a/extracted/plugins/SocketPlugin/src/common/SocketPluginImpl.c +++ b/extracted/plugins/SocketPlugin/src/common/SocketPluginImpl.c @@ -440,15 +440,6 @@ static int socketReadable(int s, int type) return -1; /* EOF */ } - - -/* answer whether the socket can be written without blocking */ - -static int socketWritable(int s) -{ - return aioFDWritable(s); -} - /* answer the error condition on the given socket */ static int socketError(int s) @@ -1216,11 +1207,11 @@ sqInt sqSocketSendDone(SocketPtr s) { if (!socketValid(s)) return false; - if (SOCKETSTATE(s) == Connected) - { - if (socketWritable(SOCKET(s))) return true; - aioHandle(SOCKET(s), dataHandler, AIO_WX); - } + + // If the socket is connected we just return true. Then the send/sendto might block, but we will use the event system + if(SOCKETSTATE(s) == Connected) + return true; + return false; } diff --git a/extracted/vm/include/common/sqaio.h b/extracted/vm/include/common/sqaio.h index 94d813b74c..00e6700caf 100644 --- a/extracted/vm/include/common/sqaio.h +++ b/extracted/vm/include/common/sqaio.h @@ -101,9 +101,6 @@ EXPORT(void) aioInterruptPoll(); */ EXPORT(void) aioWaitIfInPoll(); -EXPORT(int) aioFDWritable(int s); - - /* debugging stuff. */ #ifdef AIO_DEBUG # ifdef ACORN diff --git a/extracted/vm/src/osx/aioOSX.c b/extracted/vm/src/osx/aioOSX.c index de9316f6a2..8804c677e4 100644 --- a/extracted/vm/src/osx/aioOSX.c +++ b/extracted/vm/src/osx/aioOSX.c @@ -444,9 +444,4 @@ void AioOSXDescriptor_remove(int fd){ found = found->next; } -} - -EXPORT(int) aioFDWritable(int fd){ - // We can assume we can always write. If there is a problem the send/sendto will return EAWOULDBLOCK and we will use the event mechanism. - return 1; } \ No newline at end of file diff --git a/extracted/vm/src/unix/aio.c b/extracted/vm/src/unix/aio.c index 0374df3179..1b0b29a12e 100644 --- a/extracted/vm/src/unix/aio.c +++ b/extracted/vm/src/unix/aio.c @@ -269,11 +269,6 @@ static int fillEPollDescriptor(){ return epollDescriptor; } -EXPORT(int) aioFDWritable(int fd){ - // We can assume we can always write. If there is a problem the send/sendto will return EAWOULDBLOCK and we will use the event mechanism. - return 1; -} - static int aio_handle_events(long microSecondsTimeout){ diff --git a/extracted/vm/src/win/aioWin.c b/extracted/vm/src/win/aioWin.c index 7e4c0f42d2..f9c795cbb6 100644 --- a/extracted/vm/src/win/aioWin.c +++ b/extracted/vm/src/win/aioWin.c @@ -531,12 +531,3 @@ EXPORT(long) aioPoll(long microSeconds){ EXPORT(void) aioInterruptPoll(){ SetEvent(interruptEvent); } - -EXPORT(int) aioFDWritable(int fd){ - -/* - In Windows, we should assume the socket are always writable and then handle the issue with WSAEWOULDBLOCK error. - Once the write fails, it is registered and the socket will be written when it will not block. -*/ - return 1; -} \ No newline at end of file