Skip to content

Commit

Permalink
Merge pull request #1066 from robgjansen/syscall-eventfd
Browse files Browse the repository at this point in the history
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
robgjansen committed Jan 12, 2021
2 parents 477f83e + bd25780 commit be97c7b
Show file tree
Hide file tree
Showing 17 changed files with 586 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ set(shadow_srcs
host/descriptor/descriptor.c
host/status_listener.c
host/descriptor/descriptor_table.c
host/descriptor/eventd.c
host/descriptor/epoll.c
host/descriptor/file.c
host/descriptor/socket.c
Expand All @@ -107,6 +108,7 @@ set(shadow_srcs
host/syscall/protected.c
host/syscall/clone.c
host/syscall/epoll.c
host/syscall/eventfd.c
host/syscall/fcntl.c
host/syscall/file.c
host/syscall/fileat.c
Expand Down
15 changes: 15 additions & 0 deletions src/main/core/support/object_counter.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ struct _ObjectCounter {
ObjectCounts tcp;
ObjectCounts udp;
ObjectCounts epoll;
ObjectCounts eventd;
ObjectCounts timer;
ObjectCounts file;
ObjectCounts futex;
Expand Down Expand Up @@ -201,6 +202,11 @@ void objectcounter_incrementOne(ObjectCounter* counter, ObjectType otype, Counte
break;
}

case OBJECT_TYPE_EVENTD: {
_objectcount_incrementOne(&(counter->counters.eventd), ctype);
break;
}

case OBJECT_TYPE_TIMER: {
_objectcount_incrementOne(&(counter->counters.timer), ctype);
break;
Expand Down Expand Up @@ -272,6 +278,8 @@ void objectcounter_incrementAll(ObjectCounter* counter, ObjectCounter* increment
&(increment->counters.udp));
_objectcount_incrementAll(&(counter->counters.epoll),
&(increment->counters.epoll));
_objectcount_incrementAll(&(counter->counters.eventd),
&(increment->counters.eventd));
_objectcount_incrementAll(&(counter->counters.timer),
&(increment->counters.timer));
_objectcount_incrementAll(&(counter->counters.file),
Expand Down Expand Up @@ -333,6 +341,8 @@ const gchar* objectcounter_valuesToString(ObjectCounter* counter) {
"udp_free=%" G_GUINT64_FORMAT " "
"epoll_new=%" G_GUINT64_FORMAT " "
"epoll_free=%" G_GUINT64_FORMAT " "
"eventd_new=%" G_GUINT64_FORMAT " "
"eventd_free=%" G_GUINT64_FORMAT " "
"timer_new=%" G_GUINT64_FORMAT " "
"timer_free=%" G_GUINT64_FORMAT " "
"file_new=%" G_GUINT64_FORMAT " "
Expand Down Expand Up @@ -379,6 +389,8 @@ const gchar* objectcounter_valuesToString(ObjectCounter* counter) {
counter->counters.udp.free,
counter->counters.epoll.new,
counter->counters.epoll.free,
counter->counters.eventd.new,
counter->counters.eventd.free,
counter->counters.timer.new,
counter->counters.timer.free,
counter->counters.file.new,
Expand Down Expand Up @@ -423,6 +435,7 @@ const gchar* objectcounter_diffsToString(ObjectCounter* counter) {
"tcp=%" G_GUINT64_FORMAT " "
"udp=%" G_GUINT64_FORMAT " "
"epoll=%" G_GUINT64_FORMAT " "
"eventd=%" G_GUINT64_FORMAT " "
"timer=%" G_GUINT64_FORMAT " "
"file=%" G_GUINT64_FORMAT " "
"futex=%" G_GUINT64_FORMAT " "
Expand Down Expand Up @@ -465,6 +478,8 @@ const gchar* objectcounter_diffsToString(ObjectCounter* counter) {
counter->counters.udp.free,
counter->counters.epoll.new -
counter->counters.epoll.free,
counter->counters.eventd.new -
counter->counters.eventd.free,
counter->counters.timer.new -
counter->counters.timer.free,
counter->counters.file.new -
Expand Down
1 change: 1 addition & 0 deletions src/main/core/support/object_counter.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ enum _ObjectType {
OBJECT_TYPE_TCP,
OBJECT_TYPE_UDP,
OBJECT_TYPE_EPOLL,
OBJECT_TYPE_EVENTD,
OBJECT_TYPE_TIMER,
OBJECT_TYPE_FILE,
OBJECT_TYPE_FUTEX,
Expand Down
1 change: 1 addition & 0 deletions src/main/host/descriptor/descriptor_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ enum _DescriptorType {
DT_PIPE,
DT_UNIXSOCKET,
DT_EPOLL,
DT_EVENTD,
DT_TIMER,
DT_FILE,
};
Expand Down
149 changes: 149 additions & 0 deletions src/main/host/descriptor/eventd.c
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);
}
20 changes: 20 additions & 0 deletions src/main/host/descriptor/eventd.h
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_ */
93 changes: 93 additions & 0 deletions src/main/host/syscall/eventfd.c
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);
}
14 changes: 14 additions & 0 deletions src/main/host/syscall/eventfd.h
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_ */
3 changes: 3 additions & 0 deletions src/main/host/syscall/unistd.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include "main/host/descriptor/channel.h"
#include "main/host/descriptor/descriptor.h"
#include "main/host/descriptor/eventd.h"
#include "main/host/descriptor/file.h"
#include "main/host/descriptor/timer.h"
#include "main/host/host.h"
Expand Down Expand Up @@ -134,6 +135,7 @@ static SysCallReturn _syscallhandler_readHelper(SysCallHandler* sys, int fd,
result = file_pread((File*)desc, buf, sizeNeeded, offset);
}
break;
case DT_EVENTD: result = eventd_read((EventD*)desc, buf, sizeNeeded); break;
case DT_TIMER:
result = timer_read((Timer*)desc, buf, sizeNeeded);
break;
Expand Down Expand Up @@ -227,6 +229,7 @@ static SysCallReturn _syscallhandler_writeHelper(SysCallHandler* sys, int fd,
result = file_pwrite((File*)desc, buf, sizeNeeded, offset);
}
break;
case DT_EVENTD: result = eventd_write((EventD*)desc, buf, sizeNeeded); break;
case DT_TIMER: result = -EINVAL; break;
case DT_PIPE:
result =
Expand Down
Loading

0 comments on commit be97c7b

Please sign in to comment.