-
Notifications
You must be signed in to change notification settings - Fork 237
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1066 from robgjansen/syscall-eventfd
Tests and support for eventfd syscall Add test cases and Shadow support for the eventfd() syscall and read() and write() on eventfd descriptors. #849
- Loading branch information
Showing
17 changed files
with
586 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ enum _DescriptorType { | |
DT_PIPE, | ||
DT_UNIXSOCKET, | ||
DT_EPOLL, | ||
DT_EVENTD, | ||
DT_TIMER, | ||
DT_FILE, | ||
}; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
/* | ||
* The Shadow Simulator | ||
* See LICENSE for licensing information | ||
*/ | ||
|
||
#include "main/host/descriptor/eventd.h" | ||
|
||
#include <errno.h> | ||
#include <stdbool.h> | ||
#include <string.h> | ||
|
||
#include "main/core/support/definitions.h" | ||
#include "main/core/support/object_counter.h" | ||
#include "main/core/worker.h" | ||
#include "main/host/descriptor/descriptor.h" | ||
#include "main/host/descriptor/descriptor_types.h" | ||
#include "support/logger/logger.h" | ||
|
||
struct _EventD { | ||
Descriptor super; | ||
|
||
uint64_t counter; | ||
bool is_closed; | ||
bool is_semaphore; | ||
|
||
MAGIC_DECLARE; | ||
}; | ||
|
||
static EventD* _eventfd_fromDescriptor(Descriptor* descriptor) { | ||
utility_assert(descriptor_getType(descriptor) == DT_EVENTD); | ||
return (EventD*)descriptor; | ||
} | ||
|
||
static gboolean _eventd_close(Descriptor* descriptor) { | ||
EventD* eventd = _eventfd_fromDescriptor(descriptor); | ||
MAGIC_ASSERT(eventd); | ||
|
||
debug("event fd %i closing now", eventd->super.handle); | ||
|
||
eventd->is_closed = true; | ||
descriptor_adjustStatus(&(eventd->super), STATUS_DESCRIPTOR_ACTIVE, FALSE); | ||
|
||
if (eventd->super.handle > 0) { | ||
return TRUE; // deregister from process | ||
} else { | ||
return FALSE; // we are not owned by a process | ||
} | ||
} | ||
|
||
static void _eventd_free(Descriptor* descriptor) { | ||
EventD* eventd = _eventfd_fromDescriptor(descriptor); | ||
MAGIC_ASSERT(eventd); | ||
|
||
descriptor_clear((Descriptor*)eventd); | ||
MAGIC_CLEAR(eventd); | ||
|
||
free(eventd); | ||
worker_countObject(OBJECT_TYPE_EVENTD, COUNTER_TYPE_FREE); | ||
} | ||
|
||
static DescriptorFunctionTable _eventdFunctions = {_eventd_close, _eventd_free, MAGIC_VALUE}; | ||
|
||
static void _eventd_updateStatus(EventD* eventd) { | ||
// Set the descriptor as readable if we have a non-zero counter. | ||
descriptor_adjustStatus( | ||
&eventd->super, STATUS_DESCRIPTOR_READABLE, eventd->counter > 0 ? 1 : 0); | ||
// Set the descriptor as writable if we can write a value of at least 1. | ||
descriptor_adjustStatus( | ||
&eventd->super, STATUS_DESCRIPTOR_WRITABLE, eventd->counter < UINT64_MAX - 1 ? 1 : 0); | ||
} | ||
|
||
EventD* eventd_new(unsigned int counter_init_val, bool is_semaphore) { | ||
EventD* eventd = malloc(sizeof(*eventd)); | ||
*eventd = (EventD){ | ||
.counter = (uint64_t)counter_init_val, .is_semaphore = is_semaphore, MAGIC_INITIALIZER}; | ||
|
||
descriptor_init(&(eventd->super), DT_EVENTD, &_eventdFunctions); | ||
descriptor_adjustStatus(&(eventd->super), STATUS_DESCRIPTOR_ACTIVE, TRUE); | ||
|
||
worker_countObject(OBJECT_TYPE_EVENTD, COUNTER_TYPE_NEW); | ||
_eventd_updateStatus(eventd); | ||
|
||
return eventd; | ||
} | ||
|
||
ssize_t eventd_read(EventD* eventd, void* buf, size_t buflen) { | ||
MAGIC_ASSERT(eventd); | ||
|
||
debug("Trying to read %zu bytes from event fd %i with counter %lu", buflen, | ||
eventd->super.handle, (long unsigned int)eventd->counter); | ||
|
||
if (buflen < sizeof(uint64_t)) { | ||
debug("Reading from eventd requires buffer of at least 8 bytes"); | ||
return -EINVAL; | ||
} | ||
|
||
if (eventd->counter == 0) { | ||
debug("Eventd counter is 0 and cannot be read right now"); | ||
return -EWOULDBLOCK; | ||
} | ||
|
||
// Behavior defined in `man eventfd` | ||
if (eventd->is_semaphore) { | ||
const uint64_t one = 1; | ||
memcpy(buf, &one, sizeof(uint64_t)); | ||
eventd->counter--; | ||
} else { | ||
memcpy(buf, &(eventd->counter), sizeof(uint64_t)); | ||
eventd->counter = 0; | ||
} | ||
|
||
_eventd_updateStatus(eventd); | ||
|
||
// successfully read the counter update value | ||
return sizeof(uint64_t); | ||
} | ||
|
||
ssize_t eventd_write(EventD* eventd, const void* buf, size_t buflen) { | ||
MAGIC_ASSERT(eventd); | ||
|
||
debug("Trying to write %zu bytes to event fd %i with counter %lu", buflen, eventd->super.handle, | ||
(long unsigned int)eventd->counter); | ||
|
||
if (buflen < sizeof(uint64_t)) { | ||
debug("Writing to eventd requires a buffer with at least 8 bytes"); | ||
return -EINVAL; | ||
} | ||
|
||
uint64_t value; | ||
memcpy(&value, buf, sizeof(uint64_t)); | ||
|
||
if (value == UINT64_MAX) { | ||
debug("We do not allow writing the max counter value"); | ||
return -EINVAL; | ||
} | ||
|
||
const uint64_t max_allowed = UINT64_MAX - 1; | ||
if (value > max_allowed - eventd->counter) { | ||
debug("The write value does not currently fit into the counter"); | ||
return -EWOULDBLOCK; | ||
} else { | ||
eventd->counter += value; | ||
} | ||
|
||
_eventd_updateStatus(eventd); | ||
|
||
// successfully wrote the counter update value | ||
return sizeof(uint64_t); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* | ||
* The Shadow Simulator | ||
* See LICENSE for licensing information | ||
*/ | ||
|
||
#ifndef SRC_MAIN_HOST_DESCRIPTOR_EVENTD_H_ | ||
#define SRC_MAIN_HOST_DESCRIPTOR_EVENTD_H_ | ||
|
||
#include <stdbool.h> | ||
#include <unistd.h> | ||
|
||
typedef struct _EventD EventD; | ||
|
||
/* free this with descriptor_free() */ | ||
EventD* eventd_new(unsigned int counter_init_val, bool is_semaphore); | ||
|
||
ssize_t eventd_read(EventD* eventfd, void* buf, size_t buflen); | ||
ssize_t eventd_write(EventD* eventfd, const void* buf, size_t buflen); | ||
|
||
#endif /* SRC_MAIN_HOST_DESCRIPTOR_EVENTD_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
/* | ||
* The Shadow Simulator | ||
* See LICENSE for licensing information | ||
*/ | ||
|
||
#include "main/host/syscall/eventfd.h" | ||
|
||
#include <errno.h> | ||
#include <stddef.h> | ||
#include <sys/eventfd.h> | ||
|
||
#include "main/core/worker.h" | ||
#include "main/host/descriptor/eventd.h" | ||
#include "main/host/process.h" | ||
#include "main/host/syscall/protected.h" | ||
#include "main/host/thread.h" | ||
#include "support/logger/logger.h" | ||
|
||
/////////////////////////////////////////////////////////// | ||
// Helpers | ||
/////////////////////////////////////////////////////////// | ||
|
||
static int _syscallhandler_validateEventFDHelper(SysCallHandler* sys, int efd, | ||
EventD** event_desc_out) { | ||
/* Check that fd is within bounds. */ | ||
if (efd < 0) { | ||
info("descriptor %i out of bounds", efd); | ||
return -EBADF; | ||
} | ||
|
||
/* Check if this is a virtual Shadow descriptor. */ | ||
Descriptor* desc = process_getRegisteredDescriptor(sys->process, efd); | ||
if (desc && event_desc_out) { | ||
*event_desc_out = (EventD*)desc; | ||
} | ||
|
||
int errcode = _syscallhandler_validateDescriptor(desc, DT_EVENTD); | ||
if (errcode) { | ||
info("descriptor %i is invalid", efd); | ||
return errcode; | ||
} | ||
|
||
/* Now we know we have a valid eventd object. */ | ||
return 0; | ||
} | ||
|
||
static SysCallReturn _syscallhandler_eventfdHelper(SysCallHandler* sys, unsigned int initval, | ||
int flags) { | ||
debug("eventfd() called with initval %u and flags %i", initval, flags); | ||
|
||
/* any of 3 values can be bitwise ORed into flags */ | ||
if (flags & ~(EFD_CLOEXEC | EFD_NONBLOCK | EFD_SEMAPHORE)) { | ||
info("Invalid eventfd flags were given: %i", flags); | ||
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -EINVAL}; | ||
} | ||
|
||
/* Create the eventd object and double check that it's valid. */ | ||
EventD* eventd = eventd_new(initval, flags & EFD_SEMAPHORE ? 1 : 0); | ||
int efd = process_registerDescriptor(sys->process, (Descriptor*)eventd); | ||
|
||
#ifdef DEBUG | ||
/* This should always be a valid descriptor. */ | ||
int errcode = _syscallhandler_validateEventFDHelper(sys, efd, NULL); | ||
if (errcode != 0) { | ||
error("Unable to find eventfd %i that we just created.", efd); | ||
} | ||
utility_assert(errcode == 0); | ||
#endif | ||
|
||
/* Set any options that were given. */ | ||
if (flags & EFD_NONBLOCK) { | ||
descriptor_addFlags((Descriptor*)eventd, O_NONBLOCK); | ||
} | ||
if (flags & EFD_CLOEXEC) { | ||
descriptor_addFlags((Descriptor*)eventd, O_CLOEXEC); | ||
} | ||
|
||
debug("eventfd() returning fd %i", efd); | ||
|
||
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = efd}; | ||
} | ||
|
||
/////////////////////////////////////////////////////////// | ||
// System Calls | ||
/////////////////////////////////////////////////////////// | ||
|
||
SysCallReturn syscallhandler_eventfd(SysCallHandler* sys, const SysCallArgs* args) { | ||
return _syscallhandler_eventfdHelper(sys, args->args[0].as_u64, args->args[1].as_i64); | ||
} | ||
|
||
SysCallReturn syscallhandler_eventfd2(SysCallHandler* sys, const SysCallArgs* args) { | ||
return _syscallhandler_eventfdHelper(sys, args->args[0].as_u64, args->args[1].as_i64); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/* | ||
* The Shadow Simulator | ||
* See LICENSE for licensing information | ||
*/ | ||
|
||
#ifndef SRC_MAIN_HOST_SYSCALL_EVENTFD_H_ | ||
#define SRC_MAIN_HOST_SYSCALL_EVENTFD_H_ | ||
|
||
#include "main/host/syscall/protected.h" | ||
|
||
SYSCALL_HANDLER(eventfd); | ||
SYSCALL_HANDLER(eventfd2); | ||
|
||
#endif /* SRC_MAIN_HOST_SYSCALL_EVENTFD_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.