diff --git a/LibOS/shim/include/shim_atomic.h b/LibOS/shim/include/shim_atomic.h
deleted file mode 100644
index c608ba62..00000000
--- a/LibOS/shim/include/shim_atomic.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
-/* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
-
-/* Copyright (C) 2014 OSCAR lab, Stony Brook University
- This file is part of Graphene Library OS.
-
- Graphene Library OS is free software: you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- Graphene Library OS is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see . */
-
-/*
- * shim_atomic.h
- *
- * This file contains functions and macros for atomic operations.
- */
-
-#ifndef _SHIM_ATOMIC_H_
-#define _SHIM_ATOMIC_H_
-
-#include "shim_types.h"
-
-/* Optimization barrier */
-/* The "volatile" is due to gcc bugs */
-#define barrier() __asm__ __volatile__("": : :"memory")
-
-#ifdef __x86_64__
-/*
- * Some non-Intel clones support of order store. wmb() ceases to be a
- * nop for these.
- */
-# define cpu_relax() asm volatile ("rep; nop" ::: "memory")
-# define mb() asm volatile ("mfence" ::: "memory")
-# define rmb() asm volatile ("lfence" ::: "memory")
-# define wmb() asm volatile ("sfence" ::: "memory")
-#endif
-
-#define LOCK_PREFIX "\n\tlock; "
-
-#define ATOMIC_INIT(i) { (i) }
-
-static inline int atomic_read (const struct shim_atomic * v)
-{
- return (*(volatile long *)&(v)->counter);
-}
-
-static inline void atomic_set (struct shim_atomic * v, int i)
-{
- v->counter = i;
-}
-
-static inline void atomic_add (int i, struct shim_atomic * v)
-{
- asm volatile(LOCK_PREFIX "addl %1,%0"
- : "+m" (v->counter)
- : "ir" (i));
-}
-
-static inline void atomic_sub (int i, struct shim_atomic * v)
-{
- asm volatile(LOCK_PREFIX "subl %1,%0"
- : "+m" (v->counter)
- : "ir" (i));
-}
-
-static inline int atomic_sub_and_test (int i, struct shim_atomic * v)
-{
- unsigned char c;
- asm volatile(LOCK_PREFIX "subl %2,%0; sete %1"
- : "+m" (v->counter), "=qm" (c)
- : "ir" (i) : "memory");
- return c;
-}
-
-static inline void atomic_inc (struct shim_atomic * v)
-{
- asm volatile(LOCK_PREFIX "incl %0"
- : "+m" (v->counter));
-}
-
-static inline int atomic_inc_and_test (struct shim_atomic * v)
-{
- unsigned char c;
- asm volatile(LOCK_PREFIX "incl %0; sete %1"
- : "+m" (v->counter), "=qm" (c)
- : : "memory");
- return c != 0;
-}
-
-static inline void atomic_dec (struct shim_atomic * v)
-{
- asm volatile(LOCK_PREFIX "decl %0"
- : "+m" (v->counter));
-}
-
-static inline int atomic_dec_and_test (struct shim_atomic * v)
-{
- unsigned char c;
- asm volatile(LOCK_PREFIX "decl %0; sete %1"
- : "+m" (v->counter), "=qm" (c)
- : : "memory");
- return c != 0;
-}
-
-#undef LOCK_PREFIX
-
-#ifndef __i386__
-# include "cmpxchg_64.h"
-#else
-# include "cmpxchg_32.h"
-#endif
-
-static inline int atomic_cmpxchg (struct shim_atomic * v, int old, int new)
-{
- return cmpxchg(&v->counter, old, new);
-}
-
-static inline int atomic_xchg (struct shim_atomic * v, int new)
-{
- return xchg(&v->counter, new);
-}
-
-#endif /* _SHIM_ATOMIC_H_ */
diff --git a/LibOS/shim/include/shim_handle.h b/LibOS/shim/include/shim_handle.h
index d9ed557e..f74fa1f1 100644
--- a/LibOS/shim/include/shim_handle.h
+++ b/LibOS/shim/include/shim_handle.h
@@ -69,11 +69,11 @@ enum shim_file_type {
struct shim_file_data {
LOCKTYPE lock;
- struct shim_atomic version;
+ struct atomic_int version;
bool queried;
enum shim_file_type type;
mode_t mode;
- struct shim_atomic size;
+ struct atomic_int size;
struct shim_qstr host_uri;
unsigned long atime;
unsigned long mtime;
diff --git a/LibOS/shim/include/shim_internal.h b/LibOS/shim/include/shim_internal.h
index c0fedde9..c1646b17 100644
--- a/LibOS/shim/include/shim_internal.h
+++ b/LibOS/shim/include/shim_internal.h
@@ -39,7 +39,7 @@
#include
#include
-#include
+#include
#include
/* important macros */
@@ -474,7 +474,7 @@ static inline void enable_preempt (shim_tcb_t * tcb)
#define create_lock(l) \
do { \
- (l).lock = DkSemaphoreCreate(0, 1); \
+ (l).lock = DkMutexCreate(0); \
/* (l).owner = LOCK_FREE; */ \
/* (l).reowned = 0; */ \
} while (0)
@@ -532,7 +532,7 @@ static inline void __unlock (LOCKTYPE * l)
#endif
l->owner = 0;
- DkSemaphoreRelease(l->lock, 1);
+ DkMutexRelease(l->lock);
enable_preempt(tcb);
}
diff --git a/LibOS/shim/include/shim_ipc.h b/LibOS/shim/include/shim_ipc.h
index 7a5b1ef4..6d8c4a33 100644
--- a/LibOS/shim/include/shim_ipc.h
+++ b/LibOS/shim/include/shim_ipc.h
@@ -604,7 +604,6 @@ void ipc_parent_exit (struct shim_ipc_port * port, IDTYPE vmid,
void ipc_child_exit (struct shim_ipc_port * port, IDTYPE vmid,
unsigned int exitcode, unsigned int term_signal);
-int create_ipc_helper (void);
int exit_with_ipc_helper (bool handover);
#define IPC_FORCE_RECONNECT ((void *) -1)
diff --git a/LibOS/shim/include/shim_signal.h b/LibOS/shim/include/shim_signal.h
index 7b007c2d..1f7cc25d 100644
--- a/LibOS/shim/include/shim_signal.h
+++ b/LibOS/shim/include/shim_signal.h
@@ -105,7 +105,7 @@ struct shim_signal {
#define MAX_SIGNAL_LOG 32
struct shim_signal_log {
- struct shim_atomic head, tail;
+ struct atomic_int head, tail;
struct shim_signal * logs[MAX_SIGNAL_LOG];
};
diff --git a/LibOS/shim/include/shim_thread.h b/LibOS/shim/include/shim_thread.h
index 48b46a15..a159ace9 100644
--- a/LibOS/shim/include/shim_thread.h
+++ b/LibOS/shim/include/shim_thread.h
@@ -57,7 +57,7 @@ struct shim_thread {
/* signal handling */
__sigset_t signal_mask;
struct shim_signal_handle signal_handles[NUM_SIGS];
- struct shim_atomic has_signal;
+ struct atomic_int has_signal;
struct shim_signal_log * signal_logs;
bool suspend_on_signal;
stack_t signal_altstack;
diff --git a/LibOS/shim/include/shim_types.h b/LibOS/shim/include/shim_types.h
index 247e543c..c5e909c9 100644
--- a/LibOS/shim/include/shim_types.h
+++ b/LibOS/shim/include/shim_types.h
@@ -462,15 +462,7 @@ typedef uint16_t FDTYPE;
typedef unsigned long LEASETYPE;
typedef unsigned long HASHTYPE;
-struct shim_atomic {
-#ifndef __i386__
- long counter;
-#else
- int counter;
-#endif
-};
-
-typedef struct shim_atomic REFTYPE;
+typedef struct atomic_int REFTYPE;
#include
diff --git a/LibOS/shim/src/fs/shim_fs.c b/LibOS/shim/src/fs/shim_fs.c
index c92af363..7af28886 100644
--- a/LibOS/shim/src/fs/shim_fs.c
+++ b/LibOS/shim/src/fs/shim_fs.c
@@ -447,7 +447,7 @@ int mount_fs (const char * type, const char * uri, const char * mount_point,
* entry (until the unmount). But we shouldn't also hold the reference on
* dent from the validation step. Drop it here */
put_dentry(dent2);
-
+
ret = __mount_fs(mount, dent);
// If we made it this far and the dentry is still negative, clear
diff --git a/LibOS/shim/src/ipc/shim_ipc.c b/LibOS/shim/src/ipc/shim_ipc.c
index bd536a97..ef26af7e 100644
--- a/LibOS/shim/src/ipc/shim_ipc.c
+++ b/LibOS/shim/src/ipc/shim_ipc.c
@@ -399,7 +399,7 @@ int close_ipc_message_duplex (struct shim_ipc_msg_obj * msg,
return 0;
}
-static struct shim_atomic ipc_seq_counter;
+static struct atomic_int ipc_seq_counter;
int send_ipc_message_duplex (struct shim_ipc_msg_obj * msg,
struct shim_ipc_port * port, bool save,
diff --git a/LibOS/shim/src/ipc/shim_ipc_helper.c b/LibOS/shim/src/ipc/shim_ipc_helper.c
index 1dd59cb3..182d2cfa 100644
--- a/LibOS/shim/src/ipc/shim_ipc_helper.c
+++ b/LibOS/shim/src/ipc/shim_ipc_helper.c
@@ -55,12 +55,17 @@ static LISTP_TYPE(shim_ipc_port) pobj_list;
/* This points to a list of shim_ipc_port objects (by the hlist field) */
static LISTP_TYPE(shim_ipc_port) ipc_port_pool [PID_HASH_NUM];
-enum {
+/* This variable can be read without the ipc_helper_lock held, but
+ * should be modified with the ipc_helper_lock held (and in some cases,
+ * the value should be re-checked after acquiring the lock.
+ * For reads in a loop without the lock, some caution should be taken to
+ * use compiler barriers to ensure that a stale value isn't cached.
+ */
+static enum {
HELPER_UNINITIALIZED, HELPER_DELAYED, HELPER_NOTALIVE,
HELPER_ALIVE, HELPER_HANDEDOVER,
-};
+} ipc_helper_state;
-static struct shim_atomic ipc_helper_state;
static struct shim_thread * ipc_helper_thread;
static bool ipc_helper_update;
static AEVENTTYPE ipc_helper_event;
@@ -142,14 +147,29 @@ int init_ipc_ports (void)
return 0;
}
+
+static int create_ipc_helper (void);
+
+/* This function should be called as part of init, before locks or atomics are
+ * required */
int init_ipc_helper (void)
{
- bool need_helper = (atomic_read(&ipc_helper_state) == HELPER_DELAYED);
- atomic_set(&ipc_helper_state, HELPER_NOTALIVE);
+ bool need_helper = (ipc_helper_state == HELPER_DELAYED);
+ ipc_helper_state = HELPER_NOTALIVE;
create_lock(ipc_helper_lock);
create_event(&ipc_helper_event);
- if (need_helper)
+ if (need_helper) {
+ /*
+ * we are enabling multi-threading, must turn on threading
+ * before grabbing any lock
+ */
+ enable_locking();
+
+ /* Go ahead and lock the ipc helper lock here, for consistency */
+ lock(ipc_helper_lock);
create_ipc_helper();
+ unlock(ipc_helper_lock);
+ }
return 0;
}
@@ -184,11 +204,12 @@ static void __put_ipc_port (struct shim_ipc_port * pobj)
}
}
+/* This should be called with the ipc_helper_lock held */
static inline void restart_ipc_helper (bool need_create)
{
- switch (atomic_read(&ipc_helper_state)) {
+ switch (ipc_helper_state) {
case HELPER_UNINITIALIZED:
- atomic_set(&ipc_helper_state, HELPER_DELAYED);
+ ipc_helper_state = HELPER_DELAYED;
case HELPER_DELAYED:
return;
case HELPER_NOTALIVE:
@@ -274,10 +295,10 @@ void add_ipc_port (struct shim_ipc_port * port, IDTYPE vmid, int type,
lock(ipc_helper_lock);
bool need_restart = __add_ipc_port(port, vmid, type, fini);
- unlock(ipc_helper_lock);
-
if (need_restart)
restart_ipc_helper(true);
+
+ unlock(ipc_helper_lock);
}
static struct shim_ipc_port * __get_new_ipc_port (PAL_HANDLE hdl)
@@ -330,7 +351,7 @@ void add_ipc_port_by_id (IDTYPE vmid, PAL_HANDLE hdl, int type,
if (!port && !(port = __get_new_ipc_port(hdl))) {
*portptr = NULL;
- return;
+ goto out;
}
bool need_restart = __add_ipc_port(port, vmid, type, fini);
@@ -340,10 +361,11 @@ void add_ipc_port_by_id (IDTYPE vmid, PAL_HANDLE hdl, int type,
else
__put_ipc_port(port);
- unlock(ipc_helper_lock);
-
if (need_restart)
restart_ipc_helper(true);
+
+out:
+ unlock(ipc_helper_lock);
}
static bool __del_ipc_port (struct shim_ipc_port * port, int type)
@@ -391,10 +413,11 @@ void del_ipc_port (struct shim_ipc_port * port, int type)
{
lock(ipc_helper_lock);
bool need_restart = __del_ipc_port(port, type);
- unlock(ipc_helper_lock);
if (need_restart)
restart_ipc_helper(false);
+
+ unlock(ipc_helper_lock);
}
void del_ipc_port_by_id (IDTYPE vmid, int type)
@@ -415,10 +438,9 @@ void del_ipc_port_by_id (IDTYPE vmid, int type)
}
}
- unlock(ipc_helper_lock);
-
if (need_restart)
restart_ipc_helper(false);
+ unlock(ipc_helper_lock);
}
void del_ipc_port_fini (struct shim_ipc_port * port, unsigned int exitcode)
@@ -457,13 +479,12 @@ void del_ipc_port_fini (struct shim_ipc_port * port, unsigned int exitcode)
}
}
- unlock(port->msgs_lock);
-
put_ipc_port(port);
assert(REF_GET(port->ref_count) > 0);
if (need_restart)
restart_ipc_helper(false);
+ unlock(port->msgs_lock);
}
static struct shim_ipc_port * __lookup_ipc_port (IDTYPE vmid, int type)
@@ -511,10 +532,10 @@ void del_all_ipc_ports (int type)
if (pobj->pal_handle && __del_ipc_port(pobj, type))
need_restart = true;
- unlock(ipc_helper_lock);
-
if (need_restart)
restart_ipc_helper(false);
+
+ unlock(ipc_helper_lock);
}
int broadcast_ipc (struct shim_ipc_msg * msg, struct shim_ipc_port ** exclude,
@@ -799,11 +820,16 @@ static void shim_ipc_helper (void * arg)
goto update_status;
- while (atomic_read(&ipc_helper_state) == HELPER_ALIVE ||
+ /* The compiler should be careful not to cache the ipc_helper_state or
+ * else ths loop could fail to terminate on update. Use a compiler
+ * barrier to force a re-read after sleeping. */
+ while ((ipc_helper_state == HELPER_ALIVE) ||
nalive) {
/* do a global poll on all the ports */
polled = DkObjectsWaitAny(port_num + 1, local_ports, NO_TIMEOUT);
+ barrier();
+
if (!polled)
continue;
@@ -812,7 +838,8 @@ static void shim_ipc_helper (void * arg)
if (polled == ipc_event_handle) {
clear_event(&ipc_helper_event);
update_status:
- if (atomic_read(&ipc_helper_state) == HELPER_NOTALIVE)
+ barrier();
+ if (ipc_helper_state == HELPER_NOTALIVE)
goto end;
else
goto update_list;
@@ -962,13 +989,18 @@ end:
if (self->handle_map)
put_handle_map(self->handle_map);
- if (atomic_read(&ipc_helper_state) == HELPER_HANDEDOVER) {
+ /* shim_clean ultimately calls del_all_ipc_ports(), which reacquires the
+ * helper lock. Err on the side of caution by adding a barrier to ensure
+ * reading the latest ipc helper state.
+ */
+ barrier();
+ if (ipc_helper_state == HELPER_HANDEDOVER) {
debug("ipc helper thread is the last thread, process exiting\n");
shim_clean();
}
- atomic_xchg(&ipc_helper_state, HELPER_NOTALIVE);
lock(ipc_helper_lock);
+ ipc_helper_state = HELPER_NOTALIVE;
ipc_helper_thread = NULL;
unlock(ipc_helper_lock);
put_thread(self);
@@ -977,42 +1009,30 @@ end:
DkThreadExit();
}
-int create_ipc_helper (void)
+/* This function shoudl be called with the ipc_helper_lock held */
+static int create_ipc_helper (void)
{
int ret = 0;
- if (atomic_read(&ipc_helper_state) == HELPER_ALIVE)
+ /* If we are holding the lock, no barrier is needed here, as
+ * the lock (and new function) form an implicit barrier, and
+ * any "recent" changes should have come from this thread */
+ if (ipc_helper_state == HELPER_ALIVE)
return 0;
- /*
- * we are enabling multi-threading, must turn on threading
- * before grabbing any lock
- */
- enable_locking();
-
struct shim_thread * new = get_new_internal_thread();
if (!new)
return -ENOMEM;
- lock(ipc_helper_lock);
- if (atomic_read(&ipc_helper_state) == HELPER_ALIVE) {
- unlock(ipc_helper_lock);
- put_thread(new);
- return 0;
- }
-
ipc_helper_thread = new;
- atomic_xchg(&ipc_helper_state, HELPER_ALIVE);
- unlock(ipc_helper_lock);
+ ipc_helper_state = HELPER_ALIVE;
PAL_HANDLE handle = thread_create(shim_ipc_helper, new, 0);
if (!handle) {
ret = -PAL_ERRNO;
- lock(ipc_helper_lock);
ipc_helper_thread = NULL;
- atomic_xchg(&ipc_helper_state, HELPER_NOTALIVE);
- unlock(ipc_helper_lock);
+ ipc_helper_state = HELPER_NOTALIVE;
put_thread(new);
return ret;
}
@@ -1023,7 +1043,7 @@ int create_ipc_helper (void)
int exit_with_ipc_helper (bool handover)
{
- if (IN_HELPER() || atomic_read(&ipc_helper_state) != HELPER_ALIVE)
+ if (IN_HELPER() || ipc_helper_state != HELPER_ALIVE)
return 0;
lock(ipc_helper_lock);
@@ -1036,7 +1056,6 @@ int exit_with_ipc_helper (bool handover)
break;
}
}
- unlock(ipc_helper_lock);
int new_state = HELPER_NOTALIVE;
if (handover) {
@@ -1046,10 +1065,27 @@ int exit_with_ipc_helper (bool handover)
debug("exiting ipc helper\n");
}
- atomic_xchg(&ipc_helper_state, new_state);
+ ipc_helper_state = new_state;
+ unlock(ipc_helper_lock);
+
set_event(&ipc_helper_event, 1);
- return (new_state == HELPER_NOTALIVE) ? 0 : -EAGAIN;
+ if (new_state != HELPER_NOTALIVE) {
+ return -EAGAIN;
+ } else {
+ /* We could get here via a signal handler invoked during
+ * receive_ipc_message. Let that complete so that whoever
+ * generated the signal doesn't hang waiting for IPC_RESP. */
+ int loops = 0;
+ while (ipc_helper_thread != NULL && loops++ < 2000) {
+ barrier();
+ DkThreadDelayExecution(1000);
+ }
+ if (ipc_helper_thread != NULL) {
+ debug("timed out waiting for ipc helper to exit\n");
+ }
+ return 0;
+ }
}
int terminate_ipc_helper (void)
@@ -1063,7 +1099,7 @@ int terminate_ipc_helper (void)
}
debug("terminating ipc helper\n");
- atomic_xchg(&ipc_helper_state, HELPER_NOTALIVE);
+ ipc_helper_state = HELPER_NOTALIVE;
set_event(&ipc_helper_event, 1);
unlock(ipc_helper_lock);
return 0;
diff --git a/LibOS/shim/src/shim_async.c b/LibOS/shim/src/shim_async.c
index d3c7aaca..55acaaba 100644
--- a/LibOS/shim/src/shim_async.c
+++ b/LibOS/shim/src/shim_async.c
@@ -44,9 +44,10 @@ struct async_event {
DEFINE_LISTP(async_event);
static LISTP_TYPE(async_event) async_list;
-enum { HELPER_NOTALIVE, HELPER_ALIVE };
+/* This variable can be read without the async_helper_lock held, but is always
+ * modified with it held. */
+static enum { HELPER_NOTALIVE, HELPER_ALIVE } async_helper_state;
-static struct shim_atomic async_helper_state;
static struct shim_thread * async_helper_thread;
static AEVENTTYPE async_helper_event;
@@ -110,13 +111,17 @@ int install_async_event (PAL_HANDLE object, unsigned long time,
if (atomic_read(&async_helper_state) == HELPER_NOTALIVE)
create_async_helper();
+ unlock(async_helper_lock);
+
set_event(&async_helper_event, 1);
return 0;
}
int init_async (void)
{
- atomic_set(&async_helper_state, HELPER_NOTALIVE);
+ /* This is early enough in init that we can write this variable without
+ * the lock. */
+ async_helper_state = HELPER_NOTALIVE;
create_lock(async_helper_lock);
create_event(&async_helper_event);
return 0;
@@ -164,7 +169,10 @@ static void shim_async_helper (void * arg)
goto update_status;
- while (atomic_read(&async_helper_state) == HELPER_ALIVE) {
+ /* This loop should be careful to use a barrier after sleeping
+ * to ensure that the while breaks once async_helper_state changes.
+ */
+ while (async_helper_state == HELPER_ALIVE) {
unsigned long sleep_time;
if (next_event) {
sleep_time = next_event->expire_time - latest_time;
@@ -178,7 +186,8 @@ static void shim_async_helper (void * arg)
}
polled = DkObjectsWaitAny(object_num + 1, local_objects, sleep_time);
-
+ barrier();
+
if (!polled) {
if (next_event) {
debug("async event trigger at %llu\n",
@@ -199,7 +208,7 @@ static void shim_async_helper (void * arg)
clear_event(&async_helper_event);
update_status:
latest_time = DkSystemTimeQuery();
- if (atomic_read(&async_helper_state) == HELPER_NOTALIVE) {
+ if (async_helper_state == HELPER_NOTALIVE) {
break;
} else {
lock(async_helper_lock);
@@ -265,8 +274,8 @@ update_list:
}
}
- atomic_set(&async_helper_state, HELPER_NOTALIVE);
lock(async_helper_lock);
+ async_helper_state = HELPER_NOTALIVE;
async_helper_thread = NULL;
unlock(async_helper_lock);
put_thread(self);
@@ -275,11 +284,12 @@ update_list:
DkThreadExit();
}
+/* This should be called with the async_helper_lock held */
int create_async_helper (void)
{
int ret = 0;
- if (atomic_read(&async_helper_state) == HELPER_ALIVE)
+ if (async_helper_state == HELPER_ALIVE)
return 0;
enable_locking();
@@ -288,40 +298,32 @@ int create_async_helper (void)
if (!new)
return -ENOMEM;
- lock(async_helper_lock);
- if (atomic_read(&async_helper_state) == HELPER_ALIVE) {
- unlock(async_helper_lock);
- put_thread(new);
- return 0;
- }
-
- async_helper_thread = new;
- atomic_xchg(&async_helper_state, HELPER_ALIVE);
- unlock(async_helper_lock);
-
PAL_HANDLE handle = thread_create(shim_async_helper, new, 0);
if (!handle) {
ret = -PAL_ERRNO;
- lock(async_helper_lock);
async_helper_thread = NULL;
- atomic_xchg(&async_helper_state, HELPER_NOTALIVE);
- unlock(async_helper_lock);
+ async_helper_state = HELPER_NOTALIVE;
put_thread(new);
return ret;
}
new->pal_handle = handle;
+
+ /* Publish new and update the state once fully initialized */
+ async_helper_thread = new;
+ async_helper_state = HELPER_ALIVE;
+
return 0;
}
int terminate_async_helper (void)
{
- if (atomic_read(&async_helper_state) != HELPER_ALIVE)
+ if (async_helper_state != HELPER_ALIVE)
return 0;
lock(async_helper_lock);
- atomic_xchg(&async_helper_state, HELPER_NOTALIVE);
+ async_helper_state = HELPER_NOTALIVE;
unlock(async_helper_lock);
set_event(&async_helper_event, 1);
return 0;
diff --git a/LibOS/shim/src/shim_init.c b/LibOS/shim/src/shim_init.c
index 6a313951..630e4a0a 100644
--- a/LibOS/shim/src/shim_init.c
+++ b/LibOS/shim/src/shim_init.c
@@ -1074,7 +1074,7 @@ static void print_profile_result (PAL_HANDLE hdl, struct shim_profile * root,
}
#endif /* PROFILE */
-static struct shim_atomic in_terminate = { .counter = 0, };
+static struct atomic_int in_terminate = { .counter = 0, };
int shim_terminate (void)
{
diff --git a/LibOS/shim/test/apps/ltp/PASSED b/LibOS/shim/test/apps/ltp/PASSED
index 6bb15ab6..34eafb76 100644
--- a/LibOS/shim/test/apps/ltp/PASSED
+++ b/LibOS/shim/test/apps/ltp/PASSED
@@ -945,8 +945,6 @@ waitpid01,2
waitpid02,1
waitpid02,2
waitpid02,3
-waitpid03,1
-waitpid03,2
waitpid05,1
waitpid05,2
waitpid05,3
diff --git a/Pal/include/atomic.h b/Pal/include/atomic.h
deleted file mode 100644
index 74532f1d..00000000
--- a/Pal/include/atomic.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
-/* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
-
-#ifndef _SHIM_ATOMIC_H_
-#define _SHIM_ATOMIC_H_
-
-#define LOCK_PREFIX "\n\tlock; "
-
-#define ATOMIC_INIT(i) { (i) }
-
-static inline volatile int atomic_read (const struct atomic_int * v)
-{
- return v->counter;
-}
-
-static inline void atomic_set (struct atomic_int * v, int i)
-{
- v->counter = i;
-}
-
-static inline void atomic_add (int i, struct atomic_int * v)
-{
- asm volatile(LOCK_PREFIX "addl %1,%0"
- : "+m" (v->counter)
- : "ir" (i));
-}
-
-static inline void atomic_sub (int i, struct atomic_int * v)
-{
- asm volatile(LOCK_PREFIX "subl %1,%0"
- : "+m" (v->counter)
- : "ir" (i));
-}
-
-static inline int atomic_sub_and_test (int i, struct atomic_int * v)
-{
- unsigned char c;
- asm volatile(LOCK_PREFIX "subl %2,%0; sete %1"
- : "+m" (v->counter), "=qm" (c)
- : "ir" (i) : "memory");
- return c;
-}
-
-/* Return 0 if the value drops below zero, 1 if >= 0 */
-static inline int atomic_sub_and_test_nonnegative (int i, struct atomic_int * v)
-{
- unsigned char c;
- asm volatile(LOCK_PREFIX "subl %2,%0; setns %1"
- : "+m" (v->counter), "=qm" (c)
- : "ir" (i) : "memory");
- return c;
-}
-
-static inline void atomic_inc (struct atomic_int * v)
-{
- asm volatile(LOCK_PREFIX "incl %0"
- : "+m" (v->counter));
-}
-
-static inline int atomic_inc_and_test (struct atomic_int * v)
-{
- unsigned char c;
- asm volatile(LOCK_PREFIX "incl %0; sete %1"
- : "+m" (v->counter), "=qm" (c)
- : : "memory");
- return c != 0;
-}
-
-static inline void atomic_dec (struct atomic_int * v)
-{
- asm volatile(LOCK_PREFIX "decl %0"
- : "+m" (v->counter));
-}
-
-static inline int atomic_dec_and_test (struct atomic_int * v)
-{
- unsigned char c;
- asm volatile(LOCK_PREFIX "decl %0; sete %1"
- : "+m" (v->counter), "=qm" (c)
- : : "memory");
- return c != 0;
-}
-
-/* Return 0 if the value drops below zero, 1 if >= 0 */
-static inline int atomic_dec_and_test_nonnegative (struct atomic_int * v)
-{
- unsigned char c;
- asm volatile(LOCK_PREFIX "decl %0; setns %1"
- : "+m" (v->counter), "=qm" (c)
- : : "memory");
- return c;
-}
-
-#ifndef __i386__
-# include "cmpxchg_64.h"
-#else
-# include "cmpxchg_32.h"
-#endif
-
-static inline int atomic_cmpxchg (struct atomic_int * v, int old, int new)
-{
- return cmpxchg((&v->counter), old, new);
-}
-
-static inline int atomic_xchg (struct atomic_int * v, int new)
-{
- return xchg((&v->counter), new);
-}
-
-#endif /* _ATOMIC_INT_H_ */
diff --git a/Pal/include/cmpxchg.h b/Pal/include/cmpxchg.h
deleted file mode 100644
index a460fa08..00000000
--- a/Pal/include/cmpxchg.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef CONFIG_X86_32
-# include "cmpxchg_32.h"
-#else
-# include "cmpxchg_64.h"
-#endif
diff --git a/Pal/include/cmpxchg_32.h b/Pal/include/cmpxchg_32.h
deleted file mode 100644
index 544dec0a..00000000
--- a/Pal/include/cmpxchg_32.h
+++ /dev/null
@@ -1,275 +0,0 @@
-#ifndef _ASM_X86_CMPXCHG_32_H
-#define _ASM_X86_CMPXCHG_32_H
-
-#define LOCK_PREFIX "\n\tlock; "
-/*
- * Note: if you use set64_bit(), __cmpxchg64(), or their variants, you
- * you need to test for the feature in boot_cpu_data.
- */
-
-extern void __xchg_wrong_size(void);
-
-/*
- * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
- * Note 2: xchg has side effect, so that attribute volatile is necessary,
- * but generally the primitive is invalid, *ptr is output argument. --ANK
- */
-
-struct __xchg_dummy {
- unsigned long a[100];
-};
-#define __xg(x) ((struct __xchg_dummy *)(x))
-
-#define __xchg(x, ptr, size) \
-({ \
- __typeof(*(ptr)) __x = (x); \
- switch (size) { \
- case 1: \
- asm volatile("lock; xchgb %b0,%1" \
- : "=q" (__x), "+m" (*__xg(ptr)) \
- : "0" (__x) \
- : "memory"); \
- break; \
- case 2: \
- asm volatile("lock; xchgw %w0,%1" \
- : "=r" (__x), "+m" (*__xg(ptr)) \
- : "0" (__x) \
- : "memory"); \
- break; \
- case 4: \
- asm volatile("lock; xchgl %0,%1" \
- : "=r" (__x), "+m" (*__xg(ptr)) \
- : "0" (__x) \
- : "memory"); \
- break; \
- default: \
- __xchg_wrong_size(); \
- } \
- __x; \
-})
-
-#define xchg(ptr, v) \
- __xchg((v), (ptr), sizeof(*ptr))
-
-/*
- * CMPXCHG8B only writes to the target if we had the previous
- * value in registers, otherwise it acts as a read and gives us the
- * "new previous" value. That is why there is a loop. Preloading
- * EDX:EAX is a performance optimization: in the common case it means
- * we need only one locked operation.
- *
- * A SIMD/3DNOW!/MMX/FPU 64-bit store here would require at the very
- * least an FPU save and/or %cr0.ts manipulation.
- *
- * cmpxchg8b must be used with the lock prefix here to allow the
- * instruction to be executed atomically. We need to have the reader
- * side to see the coherent 64bit value.
- */
-static inline void set_64bit(volatile u64 *ptr, u64 value)
-{
- u32 low = value;
- u32 high = value >> 32;
- u64 prev = *ptr;
-
- asm volatile("\n1:\t"
- LOCK_PREFIX "cmpxchg8b %0\n\t"
- "jnz 1b"
- : "=m" (*ptr), "+A" (prev)
- : "b" (low), "c" (high)
- : "memory");
-}
-
-extern void __cmpxchg_wrong_size(void);
-
-/*
- * Atomic compare and exchange. Compare OLD with MEM, if identical,
- * store NEW in MEM. Return the initial value in MEM. Success is
- * indicated by comparing RETURN with OLD.
- */
-#define __raw_cmpxchg(ptr, old, new, size, lock) \
-({ \
- __typeof__(*(ptr)) __ret; \
- __typeof__(*(ptr)) __old = (old); \
- __typeof__(*(ptr)) __new = (new); \
- switch (size) { \
- case 1: \
- asm volatile(lock "cmpxchgb %b2,%1" \
- : "=a" (__ret), "+m" (*__xg(ptr)) \
- : "q" (__new), "0" (__old) \
- : "memory"); \
- break; \
- case 2: \
- asm volatile(lock "cmpxchgw %w2,%1" \
- : "=a" (__ret), "+m" (*__xg(ptr)) \
- : "r" (__new), "0" (__old) \
- : "memory"); \
- break; \
- case 4: \
- asm volatile(lock "cmpxchgl %2,%1" \
- : "=a" (__ret), "+m" (*__xg(ptr)) \
- : "r" (__new), "0" (__old) \
- : "memory"); \
- break; \
- default: \
- __cmpxchg_wrong_size(); \
- } \
- __ret; \
-})
-
-#define __cmpxchg(ptr, old, new, size) \
- __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
-
-#define __sync_cmpxchg(ptr, old, new, size) \
- __raw_cmpxchg((ptr), (old), (new), (size), "lock; ")
-
-#define __cmpxchg_local(ptr, old, new, size) \
- __raw_cmpxchg((ptr), (old), (new), (size), "")
-
-#ifdef CONFIG_X86_CMPXCHG
-#define __HAVE_ARCH_CMPXCHG 1
-
-#define cmpxchg(ptr, old, new) \
- __cmpxchg((ptr), (old), (new), sizeof(*ptr))
-
-#define sync_cmpxchg(ptr, old, new) \
- __sync_cmpxchg((ptr), (old), (new), sizeof(*ptr))
-
-#define cmpxchg_local(ptr, old, new) \
- __cmpxchg_local((ptr), (old), (new), sizeof(*ptr))
-#endif
-
-#ifdef CONFIG_X86_CMPXCHG64
-#define cmpxchg64(ptr, o, n) \
- ((__typeof__(*(ptr)))__cmpxchg64((ptr), (unsigned long long)(o), \
- (unsigned long long)(n)))
-#define cmpxchg64_local(ptr, o, n) \
- ((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \
- (unsigned long long)(n)))
-#endif
-
-static inline unsigned long long __cmpxchg64(volatile void *ptr,
- unsigned long long old,
- unsigned long long new)
-{
- unsigned long long prev;
- asm volatile(LOCK_PREFIX "cmpxchg8b %1"
- : "=A" (prev),
- "+m" (*__xg(ptr))
- : "b" ((unsigned long)new),
- "c" ((unsigned long)(new >> 32)),
- "0" (old)
- : "memory");
- return prev;
-}
-
-static inline unsigned long long __cmpxchg64_local(volatile void *ptr,
- unsigned long long old,
- unsigned long long new)
-{
- unsigned long long prev;
- asm volatile("cmpxchg8b %1"
- : "=A" (prev),
- "+m" (*__xg(ptr))
- : "b" ((unsigned long)new),
- "c" ((unsigned long)(new >> 32)),
- "0" (old)
- : "memory");
- return prev;
-}
-
-#ifndef CONFIG_X86_CMPXCHG
-/*
- * Building a kernel capable running on 80386. It may be necessary to
- * simulate the cmpxchg on the 80386 CPU. For that purpose we define
- * a function for each of the sizes we support.
- */
-
-extern unsigned long cmpxchg_386_u8(volatile void *, u8, u8);
-extern unsigned long cmpxchg_386_u16(volatile void *, u16, u16);
-extern unsigned long cmpxchg_386_u32(volatile void *, u32, u32);
-
-static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
- unsigned long new, int size)
-{
- switch (size) {
- case 1:
- return cmpxchg_386_u8(ptr, old, new);
- case 2:
- return cmpxchg_386_u16(ptr, old, new);
- case 4:
- return cmpxchg_386_u32(ptr, old, new);
- }
- return old;
-}
-
-#define cmpxchg(ptr, o, n) \
-({ \
- __typeof__(*(ptr)) __ret; \
- if (likely(boot_cpu_data.x86 > 3)) \
- __ret = (__typeof__(*(ptr)))__cmpxchg((ptr), \
- (unsigned long)(o), (unsigned long)(n), \
- sizeof(*(ptr))); \
- else \
- __ret = (__typeof__(*(ptr)))cmpxchg_386((ptr), \
- (unsigned long)(o), (unsigned long)(n), \
- sizeof(*(ptr))); \
- __ret; \
-})
-#define cmpxchg_local(ptr, o, n) \
-({ \
- __typeof__(*(ptr)) __ret; \
- if (likely(boot_cpu_data.x86 > 3)) \
- __ret = (__typeof__(*(ptr)))__cmpxchg_local((ptr), \
- (unsigned long)(o), (unsigned long)(n), \
- sizeof(*(ptr))); \
- else \
- __ret = (__typeof__(*(ptr)))cmpxchg_386((ptr), \
- (unsigned long)(o), (unsigned long)(n), \
- sizeof(*(ptr))); \
- __ret; \
-})
-#endif
-
-#ifndef CONFIG_X86_CMPXCHG64
-/*
- * Building a kernel capable running on 80386 and 80486. It may be necessary
- * to simulate the cmpxchg8b on the 80386 and 80486 CPU.
- */
-
-extern unsigned long long cmpxchg_486_u64(volatile void *, u64, u64);
-
-#define cmpxchg64(ptr, o, n) \
-({ \
- __typeof__(*(ptr)) __ret; \
- __typeof__(*(ptr)) __old = (o); \
- __typeof__(*(ptr)) __new = (n); \
- alternative_io(LOCK_PREFIX_HERE \
- "call cmpxchg8b_emu", \
- "lock; cmpxchg8b (%%esi)" , \
- X86_FEATURE_CX8, \
- "=A" (__ret), \
- "S" ((ptr)), "0" (__old), \
- "b" ((unsigned int)__new), \
- "c" ((unsigned int)(__new>>32)) \
- : "memory"); \
- __ret; })
-
-
-
-#define cmpxchg64_local(ptr, o, n) \
-({ \
- __typeof__(*(ptr)) __ret; \
- if (likely(boot_cpu_data.x86 > 4)) \
- __ret = (__typeof__(*(ptr)))__cmpxchg64_local((ptr), \
- (unsigned long long)(o), \
- (unsigned long long)(n)); \
- else \
- __ret = (__typeof__(*(ptr)))cmpxchg_486_u64((ptr), \
- (unsigned long long)(o), \
- (unsigned long long)(n)); \
- __ret; \
-})
-
-#endif
-
-#endif /* _ASM_X86_CMPXCHG_32_H */
diff --git a/Pal/include/cmpxchg_64.h b/Pal/include/cmpxchg_64.h
deleted file mode 100644
index 0ebbf09b..00000000
--- a/Pal/include/cmpxchg_64.h
+++ /dev/null
@@ -1,121 +0,0 @@
-#ifndef _ASM_X86_CMPXCHG_64_H
-#define _ASM_X86_CMPXCHG_64_H
-
-//#include /* Provides LOCK_PREFIX */
-
-/*
- Including the definition of LOCK_PREFIX directly here
-*/
-#define LOCK_PREFIX "\n\tlock; "
-
-#define __xg(x) ((volatile char *)(x))
-
-/*static inline void set_64bit(volatile u64 *ptr, u64 val)
-{
- *ptr = val;
-}*/
-
-extern void __xchg_wrong_size(void);
-extern void __cmpxchg_wrong_size(void);
-
-/*
- * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
- * Note 2: xchg has side effect, so that attribute volatile is necessary,
- * but generally the primitive is invalid, *ptr is output argument. --ANK
- */
-#define __xchg(x, ptr, size) \
-({ \
- __typeof(*(ptr)) __x = (x); \
- switch (size) { \
- case 1: \
- asm volatile("lock; xchgb %b0,%1" \
- : "=q" (__x), "+m" (*__xg(ptr)) \
- : "0" (__x) \
- : "memory"); \
- break; \
- case 2: \
- asm volatile("lock; xchgw %w0,%1" \
- : "=r" (__x), "+m" (*__xg(ptr)) \
- : "0" (__x) \
- : "memory"); \
- break; \
- case 4: \
- asm volatile("lock; xchgl %k0,%1" \
- : "=r" (__x), "+m" (*__xg(ptr)) \
- : "0" (__x) \
- : "memory"); \
- break; \
- case 8: \
- asm volatile("lock; xchgq %0,%1" \
- : "=r" (__x), "+m" (*__xg(ptr)) \
- : "0" (__x) \
- : "memory"); \
- break; \
- default: \
- __xchg_wrong_size(); \
- } \
- __x; \
-})
-
-#define xchg(ptr, v) \
- __xchg((v), (ptr), sizeof(*ptr))
-
-#define __HAVE_ARCH_CMPXCHG 1
-
-/*
- * Atomic compare and exchange. Compare OLD with MEM, if identical,
- * store NEW in MEM. Return the initial value in MEM. Success is
- * indicated by comparing RETURN with OLD.
- */
-#define __raw_cmpxchg(ptr, old, new, size) \
-({ \
- __typeof__(*(ptr)) __ret; \
- __typeof__(*(ptr)) __old = (old); \
- __typeof__(*(ptr)) __new = (new); \
- switch (size) { \
- case 1: \
- asm volatile(LOCK_PREFIX "cmpxchgb %b2,%1" \
- : "=a" (__ret), "+m" (*__xg(ptr)) \
- : "q" (__new), "0" (__old) \
- : "memory"); \
- break; \
- case 2: \
- asm volatile(LOCK_PREFIX "cmpxchgw %w2,%1" \
- : "=a" (__ret), "+m" (*__xg(ptr)) \
- : "r" (__new), "0" (__old) \
- : "memory"); \
- break; \
- case 4: \
- asm volatile(LOCK_PREFIX "cmpxchgl %k2,%1" \
- : "=a" (__ret), "+m" (*__xg(ptr)) \
- : "r" (__new), "0" (__old) \
- : "memory"); \
- break; \
- case 8: \
- asm volatile(LOCK_PREFIX "cmpxchgq %2,%1" \
- : "=a" (__ret), "+m" (*__xg(ptr)) \
- : "r" (__new), "0" (__old) \
- : "memory"); \
- break; \
- default: \
- __cmpxchg_wrong_size(); \
- } \
- __ret; \
-})
-
-#define cmpxchg(ptr, old, new) \
- __raw_cmpxchg((ptr), (old), (new), sizeof(*ptr))
-
-#define cmpxchg64(ptr, o, n) \
-({ \
- BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
- cmpxchg((ptr), (o), (n)); \
-})
-
-#define cmpxchg64_local(ptr, o, n) \
-({ \
- BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
- cmpxchg_local((ptr), (o), (n)); \
-})
-
-#endif /* _ASM_X86_CMPXCHG_64_H */
diff --git a/Pal/lib/atomic.h b/Pal/lib/atomic.h
new file mode 100644
index 00000000..653f96cc
--- /dev/null
+++ b/Pal/lib/atomic.h
@@ -0,0 +1,179 @@
+/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
+/* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
+
+#ifndef _SHIM_ATOMIC_H_
+#define _SHIM_ATOMIC_H_
+
+/* Copyright (C) 2014 OSCAR lab, Stony Brook University
+ * Copyright (C) 2017 Fortanix Inc, and University of North Carolina
+ * at Chapel Hill.
+ *
+ * This file defines atomic operations (And barriers) for use in
+ * Graphene.
+ *
+ * The atomic operation assembly code is taken from musl libc, which
+ * is subject to the MIT license.
+ *
+ * At this point, we primarily focus on x86_64; there are some vestigial
+ * 32-bit definitions here, but a more portable version would need to
+ * move and reimplement portions of this for 32-bit x86 (or other architectures).
+ */
+
+/*
+/----------------------------------------------------------------------
+Copyright (C) 2005-2014 Rich Felker, et al.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ ----------------------------------------------------------------------
+*/
+
+/* Optimization barrier */
+#define barrier() __asm__ __volatile__("": : :"memory")
+# define cpu_relax() __asm__ __volatile__("rep; nop" ::: "memory");
+
+#ifdef __i386__
+# define rmb() __asm__ __volatile__("lock; addl $0,0(%%esp)" ::: "memory")
+
+struct atomic_int {
+ volatile int32_t counter;
+}
+#ifdef __GNUC__
+__attribute__((aligned(sizeof(uint32_t))))
+#endif
+;
+#endif
+
+
+/* The return types below effectively assume we are dealing with a 64-bit
+ * signed value.
+ */
+#ifdef __x86_64__
+/*
+ * Some non-Intel clones support out of order store. wmb() ceases to be a
+ * nop for these.
+ */
+# define mb() __asm__ __volatile__ ("mfence" ::: "memory")
+# define rmb() __asm__ __volatile__ ("lfence" ::: "memory")
+# define wmb() __asm__ __volatile__ ("sfence" ::: "memory")
+
+struct atomic_int {
+ volatile int64_t counter;
+}
+#ifdef __GNUC__
+__attribute__((aligned(sizeof(uint64_t))))
+#endif
+;
+#endif
+
+#define LOCK_PREFIX "\n\tlock; "
+
+#define ATOMIC_INIT(i) { (i) }
+
+/* Read the value currently stored in the atomic_int */
+static inline int64_t atomic_read (const struct atomic_int * v)
+{
+ // Effectively:
+ // return v->counter;
+ int64_t i;
+ /* Use inline assembly to ensure this is one instruction */
+ __asm__ __volatile__("mov %1, %0"
+ : "=r"(i) :
+ "m"(v->counter) : "memory");
+ return i;
+}
+
+/* Does a blind write to the atomic variable */
+static inline void atomic_set (struct atomic_int * v, int64_t i)
+{
+ // Effectively:
+ // v->counter = i;
+ /* Use inline assembly to ensure this is one instruction */
+ __asm__ __volatile__("mov %2, %0"
+ : "=m"(v->counter) :
+ "m"(v->counter), "r"(i) : "memory");
+}
+
+/* Helper function that atomically adds a value to an atomic_int,
+ * and returns the _new_ value. */
+static inline int64_t _atomic_add (int64_t i, struct atomic_int * v)
+{
+ int64_t increment = i;
+ __asm__ __volatile__(
+ "lock ; xadd %0, %1"
+ : "=r"(i), "=m"(v->counter) : "0"(i) : "memory" );
+ return i + increment;
+}
+
+/* Atomically adds i to v. Does not return a value. */
+static inline void atomic_add (int64_t i, struct atomic_int * v)
+{
+ _atomic_add(i, v);
+}
+
+/* Atomically substracts i from v. Does not return a value. */
+static inline void atomic_sub (int64_t i, struct atomic_int * v)
+{
+ _atomic_add(-i, v);
+}
+
+/* Atomically adds 1 to v. Does not return a value. */
+static inline void atomic_inc (struct atomic_int * v)
+{
+ __asm__ __volatile__(
+ "lock ; incl %0"
+ : "=m"(v->counter) : "m"(v->counter) : "memory" );
+}
+
+/* Atomically substracts 1 from v. Does not return a value. */
+static inline void atomic_dec (struct atomic_int * v)
+{
+ __asm__ __volatile__(
+ "lock ; decl %0"
+ : "=m"(v->counter) : "m"(v->counter) : "memory" );
+}
+
+/* Atomically substracts 1 from v. Returns 1 if this causes the
+ value to reach 0; returns 0 otherwise. */
+static inline int64_t atomic_dec_and_test (struct atomic_int * v)
+{
+ int64_t i = _atomic_add(-1, v);
+ return i == 0;
+}
+
+/* Helper function to atomically compare-and-swap the value pointed to by p.
+ * t is the old value, s is the new value. Returns
+ * the value originally in p. */
+static inline int64_t cmpxchg(volatile int64_t *p, int64_t t, int64_t s)
+{
+ __asm__ __volatile__ (
+ "lock ; cmpxchg %3, %1"
+ : "=a"(t), "=m"(*p) : "a"(t), "r"(s) : "memory" );
+ return t;
+}
+
+/* Helper function to atomically compare-and-swap the value in v.
+ * If v == old, it sets v = new.
+ * Returns the value originally in v. */
+static inline int64_t atomic_cmpxchg (struct atomic_int * v, int64_t old, int64_t new)
+{
+ return cmpxchg(&v->counter, old, new);
+}
+
+#endif /* _ATOMIC_INT_H_ */
diff --git a/Pal/lib/crypto/adapters/mbedtls_dh.c b/Pal/lib/crypto/adapters/mbedtls_dh.c
index bccc67a3..5eee00a2 100644
--- a/Pal/lib/crypto/adapters/mbedtls_dh.c
+++ b/Pal/lib/crypto/adapters/mbedtls_dh.c
@@ -107,4 +107,3 @@ void lib_DhFinal(LIB_DH_CONTEXT *context)
/* This call zeros out context for us. */
mbedtls_dhm_free(context);
}
-
diff --git a/Pal/lib/crypto/mbedtls/mbedtls/config.h b/Pal/lib/crypto/mbedtls/mbedtls/config.h
index 3b23bf5d..0e44df6c 100644
--- a/Pal/lib/crypto/mbedtls/mbedtls/config.h
+++ b/Pal/lib/crypto/mbedtls/mbedtls/config.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2017 Fortanix, Inc.
-
+
This file is part of Graphene Library OS.
Graphene Library OS is free software: you can redistribute it and/or
diff --git a/Pal/lib/graphene/config.c b/Pal/lib/graphene/config.c
index 66723bc0..06f85188 100644
--- a/Pal/lib/graphene/config.c
+++ b/Pal/lib/graphene/config.c
@@ -177,8 +177,8 @@ int get_config_entries_size (struct config_store * store, const char * key)
}
static int __del_config (struct config_store * store,
- LISTP_TYPE(config) * root, struct config * p,
- const char * key)
+ LISTP_TYPE(config) * root,
+ struct config * p, const char * key)
{
struct config * e, * found = NULL;
int len = 0;
diff --git a/Pal/regression/00_Atomics.py b/Pal/regression/00_Atomics.py
new file mode 100644
index 00000000..9c66faa0
--- /dev/null
+++ b/Pal/regression/00_Atomics.py
@@ -0,0 +1,25 @@
+#!/usr/bin/python
+
+import os, sys, mmap
+from regression import Regression
+
+loader = os.environ['PAL_LOADER']
+is_sgx = 'SGX_RUN' in os.environ and os.environ['SGX_RUN'] == '1'
+success = True
+
+def manifest_file(file):
+ if is_sgx:
+ return file + '.manifest.sgx'
+ else:
+ return file + '.manifest'
+
+# Running AtomicMath
+regression = Regression(loader, "AtomicMath")
+
+regression.add_check(name="Atomic Math",
+ check=lambda res: "Subtract INT_MIN: Both values match 2147483648" in res[0].log and \
+ "Subtract INT_MAX: Both values match -2147483647" in res[0].log and \
+ "Subtract LLONG_MIN: Both values match -9223372036854775808" in res[0].log and \
+ "Subtract LLONG_MAX: Both values match -9223372036854775807" in res[0].log)
+
+regression.run_checks()
diff --git a/Pal/regression/00_Symbols.py b/Pal/regression/00_Symbols.py
index a1fc812a..02d51703 100644
--- a/Pal/regression/00_Symbols.py
+++ b/Pal/regression/00_Symbols.py
@@ -37,8 +37,8 @@ all_symbols = [
'DkThreadResume',
'DkSetExceptionHandler',
'DkExceptionReturn',
- 'DkSemaphoreCreate',
- 'DkSemaphoreRelease',
+ 'DkMutexCreate',
+ 'DkMutexRelease',
'DkNotificationEventCreate',
'DkSynchronizationEventCreate',
'DkEventSet',
diff --git a/Pal/regression/02_Semaphore.py b/Pal/regression/02_Semaphore.py
index e3334779..9833ec17 100644
--- a/Pal/regression/02_Semaphore.py
+++ b/Pal/regression/02_Semaphore.py
@@ -10,17 +10,11 @@ regression = Regression(loader, "Semaphore")
regression.add_check(name="Semaphore: Timeout on Locked Semaphores",
check=lambda res: "Locked binary semaphore timed out (1000)." in res[0].log and
- "Locked non-binary semaphore timed out (1000)." in res[0].log and
- "Two locked semaphores timed out (1000)." in res[0].log and
- "Locked binary semaphore timed out (0)." in res[0].log and
- "Locked non-binary semaphore timed out (0)." in res[0].log and
- "Two locked semaphores timed out (0)." in res[0].log)
+ "Locked binary semaphore timed out (0)." in res[0].log)
regression.add_check(name="Semaphore: Acquire Unlocked Semaphores",
check=lambda res: "Locked binary semaphore successfully (-1)." in res[0].log and
- "Locked non-binary semaphore successfully (-1)." in res[0].log and
- "Locked binary semaphore successfully (0)." in res[0].log and
- "Locked non-binary semaphore successfully (0)." in res[0].log)
+ "Locked binary semaphore successfully (0)." in res[0].log)
rv = regression.run_checks()
if rv: sys.exit(rv)
diff --git a/Pal/regression/AtomicMath.c b/Pal/regression/AtomicMath.c
new file mode 100644
index 00000000..52a6073f
--- /dev/null
+++ b/Pal/regression/AtomicMath.c
@@ -0,0 +1,66 @@
+/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
+/* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
+
+#include "pal.h"
+#include "pal_debug.h"
+#include
+
+#include
+#include
+
+int main (int argc, char ** argv, char ** envp)
+{
+ int64_t my_int = 0;
+ struct atomic_int a_int;
+ atomic_set(&a_int, 0);
+
+ /* Check that INT_MIN and INT_MAX wrap around consistently
+ * with atomic values.
+ *
+ * Check atomic_sub specifically.
+ */
+ my_int -= INT_MIN;
+ atomic_sub(INT_MIN, &a_int);
+
+ if (my_int == atomic_read(&a_int))
+ pal_printf("Subtract INT_MIN: Both values match %lld\n", my_int);
+ else
+ pal_printf("Subtract INT_MIN: Values do not match %lld, %lld\n", my_int, atomic_read(&a_int));
+
+ atomic_set(&a_int, 0);
+ my_int = 0;
+
+ my_int -= INT_MAX;
+ atomic_sub(INT_MAX, &a_int);
+
+ if (my_int == atomic_read(&a_int))
+ pal_printf("Subtract INT_MAX: Both values match %lld\n", my_int);
+ else
+ pal_printf("Subtract INT_MAX: Values do not match %lld, %lld\n", my_int, atomic_read(&a_int));
+
+ /* Check that 64-bit signed values also wrap properly. */
+ atomic_set(&a_int, 0);
+ my_int = 0;
+
+ my_int -= LLONG_MIN;
+ atomic_sub(LLONG_MIN, &a_int);
+
+ if (my_int == atomic_read(&a_int))
+ pal_printf("Subtract LLONG_MIN: Both values match %lld\n", my_int);
+ else
+ pal_printf("Subtract LLONG_MIN: Values do not match %lld, %lld\n", my_int, atomic_read(&a_int));
+
+ atomic_set(&a_int, 0);
+ my_int = 0;
+
+ my_int -= LLONG_MAX;
+ atomic_sub(LLONG_MAX, &a_int);
+
+ if (my_int == atomic_read(&a_int))
+ pal_printf("Subtract LLONG_MAX: Both values match %lld\n", my_int);
+ else
+ pal_printf("Subtract LLONG_MAX: Values do not match %lld, %lld\n", my_int, atomic_read(&a_int));
+
+
+ return 0;
+}
diff --git a/Pal/regression/Semaphore.c b/Pal/regression/Semaphore.c
index 5fbad081..4c943de7 100644
--- a/Pal/regression/Semaphore.c
+++ b/Pal/regression/Semaphore.c
@@ -8,7 +8,7 @@
void helper_timeout(PAL_NUM timeout) {
/* Create a binary semaphore */
- PAL_HANDLE sem1 = DkSemaphoreCreate(1, 1);
+ PAL_HANDLE sem1 = DkMutexCreate(1);
if(!sem1) {
pal_printf("Failed to create a binary semaphore\n");
@@ -22,39 +22,13 @@ void helper_timeout(PAL_NUM timeout) {
else
pal_printf("Acquired locked binary semaphore!?! Got back %p; sem1 is %p (%d)\n", rv, sem1, timeout);
- PAL_HANDLE sem2 = DkSemaphoreCreate(2, 2);
-
- if(!sem2) {
- pal_printf("Failed to create a non-binary semaphore\n");
- return;
- }
-
- /* Wait on the non-binary semaphore with a timeout */
- rv = DkObjectsWaitAny(1, &sem2, timeout);
- if (rv == NULL)
- pal_printf("Locked non-binary semaphore timed out (%d).\n", timeout);
- else
- pal_printf("Acquired locked non-binary semaphore!?! Got back %p; sem2 is %p (%d)\n", rv, sem2, timeout);
-
- /* Try waiting on both */
- PAL_HANDLE hdls[2];
- hdls[0] = sem1;
- hdls[1] = sem2;
-
- rv = DkObjectsWaitAny(2, hdls, timeout);
- if (rv == NULL)
- pal_printf("Two locked semaphores timed out (%d).\n", timeout);
- else
- pal_printf("Somehow locked one of two locked semaphore handles? %p (%d)\n", rv, timeout);
-
DkObjectClose(sem1);
- DkObjectClose(sem2);
}
void helper_success(PAL_NUM timeout) {
/* Create a binary semaphore */
- PAL_HANDLE sem1 = DkSemaphoreCreate(0, 1);
+ PAL_HANDLE sem1 = DkMutexCreate(0);
if(!sem1) {
pal_printf("Failed to create a binary semaphore\n");
@@ -68,22 +42,7 @@ void helper_success(PAL_NUM timeout) {
else
pal_printf("Failed to lock binary semaphore: Got back %p; sem1 is %p\n", rv, sem1);
- PAL_HANDLE sem2 = DkSemaphoreCreate(0, 2);
-
- if(!sem2) {
- pal_printf("Failed to create a non-binary semaphore\n");
- return;
- }
-
- /* Wait on the non-binary semaphore with a timeout */
- rv = DkObjectsWaitAny(1, &sem2, timeout);
- if (rv == sem2)
- pal_printf("Locked non-binary semaphore successfully (%d).\n", timeout);
- else
- pal_printf("Failed to lock non-binary semaphore Got back %p; sem2 is %p\n", rv, sem2);
-
DkObjectClose(sem1);
- DkObjectClose(sem2);
}
diff --git a/Pal/regression/Symbols.c b/Pal/regression/Symbols.c
index d3bcc171..3cfaf4d2 100644
--- a/Pal/regression/Symbols.c
+++ b/Pal/regression/Symbols.c
@@ -48,8 +48,8 @@ int main (int argc, char ** argv, char ** envp)
print_symbol(DkSetExceptionHandler);
print_symbol(DkExceptionReturn);
- print_symbol(DkSemaphoreCreate);
- print_symbol(DkSemaphoreRelease);
+ print_symbol(DkMutexCreate);
+ print_symbol(DkMutexRelease);
print_symbol(DkNotificationEventCreate);
print_symbol(DkSynchronizationEventCreate);
print_symbol(DkEventSet);
diff --git a/Pal/src/Makefile b/Pal/src/Makefile
index eec45692..0aab3379 100644
--- a/Pal/src/Makefile
+++ b/Pal/src/Makefile
@@ -33,7 +33,7 @@ files_to_build = $(pal_lib) $(pal_lib_post) $(pal_static) \
defs = -DIN_PAL -DHOST_TYPE="$(PAL_HOST)" -D$(PAL_HOST_MACRO) -DPAL_DIR=$(PAL_DIR) \
-DRUNTIME_DIR=$(RUNTIME_DIR)
-objs = $(addprefix db_,streams memory threading semaphore events process \
+objs = $(addprefix db_,streams memory threading mutex events process \
object main misc ipc exception rtld) slab printf
graphene_lib = .lib/graphene-lib.a
host_lib = host/$(PAL_HOST)/libpal-$(PAL_HOST).a
diff --git a/Pal/src/db_semaphore.c b/Pal/src/db_mutex.c
similarity index 63%
rename from Pal/src/db_semaphore.c
rename to Pal/src/db_mutex.c
index 53911a0a..c6455795 100644
--- a/Pal/src/db_semaphore.c
+++ b/Pal/src/db_mutex.c
@@ -18,9 +18,9 @@
along with this program. If not, see . */
/*
- * db_semaphore.c
+ * db_mutex.c
*
- * This file contains APIs that provides operations of semaphores.
+ * This file contains APIs that provides operations of mutexes.
*/
#include "pal_defs.h"
@@ -30,13 +30,14 @@
#include "api.h"
PAL_HANDLE
-DkSemaphoreCreate (PAL_NUM initialCount, PAL_NUM maxCount)
+DkMutexCreate (PAL_NUM initialCount)
{
- ENTER_PAL_CALL(DkSemaphoreCreate);
+ ENTER_PAL_CALL(DkMutexCreate);
- PAL_HANDLE handle = (PAL_HANDLE) malloc(HANDLE_SIZE(semaphore));
-
- int ret = _DkSemaphoreCreate(handle, initialCount, maxCount);
+ PAL_HANDLE handle = (PAL_HANDLE) malloc(HANDLE_SIZE(mutex));
+ SET_HANDLE_TYPE(handle, mutex);
+
+ int ret = _DkMutexCreate(handle, initialCount);
if (ret < 0) {
free(handle);
@@ -48,38 +49,39 @@ DkSemaphoreCreate (PAL_NUM initialCount, PAL_NUM maxCount)
}
void
-DkSemaphoreDestroy (PAL_HANDLE semaphoreHandle)
+DkMutexDestroy (PAL_HANDLE handle)
{
- ENTER_PAL_CALL(DkSemaphoreDestroy);
+ ENTER_PAL_CALL(DkMutexDestroy);
- if (!semaphoreHandle) {
+ if (!handle) {
_DkRaiseFailure(PAL_ERROR_INVAL);
LEAVE_PAL_CALL();
}
- _DkSemaphoreDestroy(semaphoreHandle);
+ _DkMutexDestroy(handle);
+ free(handle);
LEAVE_PAL_CALL();
}
-void DkSemaphoreRelease (PAL_HANDLE handle, PAL_NUM count)
+void DkMutexRelease (PAL_HANDLE handle)
{
- ENTER_PAL_CALL(DkSemaphoreRelease);
+ ENTER_PAL_CALL(DkMutexRelease);
if (!handle ||
- !IS_HANDLE_TYPE(handle, semaphore)) {
+ !IS_HANDLE_TYPE(handle, mutex)) {
_DkRaiseFailure(PAL_ERROR_INVAL);
LEAVE_PAL_CALL();
}
- _DkSemaphoreRelease (handle, count);
+ _DkMutexRelease (handle);
LEAVE_PAL_CALL();
}
-static int sem_wait (PAL_HANDLE handle, uint64_t timeout)
+static int mutex_wait (PAL_HANDLE handle, uint64_t timeout)
{
- return _DkSemaphoreAcquireTimeout(handle, 1, timeout);
+ return _DkMutexAcquireTimeout(handle, timeout);
}
-struct handle_ops sem_ops = {
- .wait = &sem_wait,
+struct handle_ops mutex_ops = {
+ .wait = &mutex_wait,
};
diff --git a/Pal/src/db_object.c b/Pal/src/db_object.c
index ad9fb0a7..8fd55aa6 100644
--- a/Pal/src/db_object.c
+++ b/Pal/src/db_object.c
@@ -57,7 +57,7 @@ int _DkObjectClose (PAL_HANDLE objectHandle)
if (!objectHandle || UNKNOWN_HANDLE(objectHandle))
return -PAL_ERROR_INVAL;
- if (atomic_dec_and_test_nonnegative(&HANDLE_HDR(objectHandle)->ref))
+ if (!atomic_dec_and_test(&HANDLE_HDR(objectHandle)->ref))
return 0;
const struct handle_ops * ops = HANDLE_OPS(objectHandle);
diff --git a/Pal/src/db_streams.c b/Pal/src/db_streams.c
index df928cc2..d34f2551 100644
--- a/Pal/src/db_streams.c
+++ b/Pal/src/db_streams.c
@@ -45,7 +45,7 @@ extern struct handle_ops udpsrv_ops;
extern struct hadnle_ops udppacket_ops;
extern struct handle_ops thread_ops;
extern struct handle_ops proc_ops;
-extern struct handle_ops sem_ops;
+extern struct handle_ops mutex_ops;
extern struct handle_ops event_ops;
extern struct handle_ops gipc_ops;
extern struct handle_ops mcast_ops;
@@ -65,7 +65,7 @@ const struct handle_ops * pal_handle_ops [PAL_HANDLE_TYPE_BOUND] = {
[pal_type_process] = &proc_ops,
[pal_type_mcast] = &mcast_ops,
[pal_type_thread] = &thread_ops,
- [pal_type_semaphore] = &sem_ops,
+ [pal_type_mutex] = &mutex_ops,
[pal_type_event] = &event_ops,
[pal_type_gipc] = &gipc_ops,
};
diff --git a/Pal/src/host/FreeBSD/pal_host.h b/Pal/src/host/FreeBSD/pal_host.h
index aa9c2b64..38b6d3dc 100644
--- a/Pal/src/host/FreeBSD/pal_host.h
+++ b/Pal/src/host/FreeBSD/pal_host.h
@@ -60,8 +60,8 @@ typedef union pal_handle
struct {
PAL_IDX type;
- PAL_REF ref;
PAL_FLG flags;
+ PAL_REF ref;
PAL_IDX fds[];
} __in;
diff --git a/Pal/src/host/Linux-SGX/Makefile b/Pal/src/host/Linux-SGX/Makefile
index 54acb80d..e9756819 100644
--- a/Pal/src/host/Linux-SGX/Makefile
+++ b/Pal/src/host/Linux-SGX/Makefile
@@ -7,7 +7,7 @@ host_files = libpal-Linux-SGX.a pal-sgx debugger/sgx_gdb.so
defs = -DIN_PAL -DPAL_DIR=$(PAL_DIR) -DRUNTIME_DIR=$(RUNTIME_DIR)
enclave-objs = $(addprefix db_,files devices pipes sockets streams memory \
- threading semaphore mutex events process object main rtld \
+ threading mutex events process object main rtld \
exception misc ipc spinlock) \
$(addprefix enclave_,ocalls ecalls framework pages untrusted)
enclave-asm-objs = enclave_entry
diff --git a/Pal/src/host/Linux-SGX/db_devices.c b/Pal/src/host/Linux-SGX/db_devices.c
index 8a7afdda..def4342d 100644
--- a/Pal/src/host/Linux-SGX/db_devices.c
+++ b/Pal/src/host/Linux-SGX/db_devices.c
@@ -220,6 +220,7 @@ static int dev_open (PAL_HANDLE * handle, const char * type, const char * uri,
return -PAL_ERROR_NOTSUPPORT;
PAL_HANDLE hdl = malloc(HANDLE_SIZE(dev));
+ SET_HANDLE_TYPE(hdl, dev);
hdl->dev.fd_in = PAL_IDX_POISON;
hdl->dev.fd_out = PAL_IDX_POISON;
*handle = hdl;
diff --git a/Pal/src/host/Linux-SGX/db_files.c b/Pal/src/host/Linux-SGX/db_files.c
index 23f68b4a..3b017a1e 100644
--- a/Pal/src/host/Linux-SGX/db_files.c
+++ b/Pal/src/host/Linux-SGX/db_files.c
@@ -316,7 +316,7 @@ static int file_attrquery (const char * type, const char * uri,
static int file_attrquerybyhdl (PAL_HANDLE handle,
PAL_STREAM_ATTR * attr)
{
- int fd = HANDLE_HDR(handle)->fds[0];
+ int fd = handle->file.fd;
struct stat stat_buf;
int ret = ocall_fstat(fd, &stat_buf);
@@ -330,7 +330,7 @@ static int file_attrquerybyhdl (PAL_HANDLE handle,
static int file_attrsetbyhdl (PAL_HANDLE handle,
PAL_STREAM_ATTR * attr)
{
- int fd = HANDLE_HDR(handle)->fds[0];
+ int fd = handle->file.fd;
int ret = ocall_fchmod(fd, attr->share_flags | 0600);
if (ret < 0)
return ret;
diff --git a/Pal/src/host/Linux-SGX/db_mutex.c b/Pal/src/host/Linux-SGX/db_mutex.c
index 7c8be133..27cbecdd 100644
--- a/Pal/src/host/Linux-SGX/db_mutex.c
+++ b/Pal/src/host/Linux-SGX/db_mutex.c
@@ -30,6 +30,7 @@
#include "pal.h"
#include "pal_internal.h"
#include "pal_linux.h"
+#include "pal_linux_error.h"
#include "pal_error.h"
#include "pal_debug.h"
#include "api.h"
@@ -38,33 +39,39 @@
#include
#include
#include
-
-#ifdef __i386__
-# define barrier() asm volatile("" ::: "memory");
-# define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
-# define cpu_relax() asm volatile("rep; nop" ::: "memory");
-#endif
-
-#ifdef __x86_64__
-# include
-# define barrier() asm volatile("" ::: "memory");
-# define rmb() asm volatile("lfence" ::: "memory")
-# define cpu_relax() asm volatile("rep; nop" ::: "memory");
-#endif
+#include
+#include
#define MUTEX_SPINLOCK_TIMES 100
+#define MUTEX_UNLOCKED 0
+#define MUTEX_LOCKED 1
-int _DkMutexLockTimeout (struct mutex_handle * m, int timeout)
+
+int
+_DkMutexCreate (PAL_HANDLE handle, int initialCount)
+{
+ /*
+ * Allocation and free of the handle are done outside of host-specific code.
+ * This code initializes the mutex state that is host-specific,
+ * including how initialCount is encoded.
+ */
+ SET_HANDLE_TYPE(handle, mutex);
+ atomic_set(&handle->mutex.mut.nwaiters, 0);
+ handle->mutex.mut.locked = initialCount;
+ return 0;
+}
+
+void _DkMutexDestroy (PAL_HANDLE handle)
+{
+ free(handle);
+}
+
+
+int _DkMutexLockTimeout (struct mutex_handle * m, uint64_t timeout)
{
int ret = 0;
-#ifdef DEBUG_MUTEX
- int tid = INLINE_SYSCALL(gettid, 0);
-#endif
- if (timeout == -1)
- return -_DkMutexLock(m);
-
- if (!xchg(&m->b.locked, 1))
+ if (MUTEX_UNLOCKED == cmpxchg(&m->locked, MUTEX_UNLOCKED, MUTEX_LOCKED))
goto success;
if (timeout == 0) {
@@ -72,104 +79,74 @@ int _DkMutexLockTimeout (struct mutex_handle * m, int timeout)
goto out;
}
- unsigned long waittime = timeout;
+ // Bump up the waiters count; we are probably going to block
+ atomic_inc(&m->nwaiters);
+
+ while (MUTEX_LOCKED == cmpxchg(&m->locked, MUTEX_UNLOCKED, MUTEX_LOCKED)) {
+
+ // This is broken. The mutex is in enclave memory, the URTS can't
+ // do FUTEX_WAIT on it. This call will always fail and the next level
+ // up needs to retry.
+ ret = ocall_futex((int *) m, FUTEX_WAIT, MUTEX_LOCKED, timeout == -1 ? NULL : &timeout);
- while (xchg(&m->u, 257) & 1) {
- ret = ocall_futex((int *) m, FUTEX_WAIT, 257, timeout ? &waittime : NULL);
if (ret < 0) {
- if (ret == -PAL_ERROR_TRYAGAIN) {
- xchg(&m->b.contended, 0);
+ if (-ret == EWOULDBLOCK) {
+ ret = -PAL_ERROR_TRYAGAIN;
+ atomic_dec(&m->nwaiters);
goto out;
}
-#ifdef DEBUG_MUTEX
- printf("futex failed (err = %d)\n", ERRNO(ret));
-#endif
+ ret = unix_to_pal_error(ERRNO(ret));
+ atomic_dec(&m->nwaiters);
goto out;
}
}
+ atomic_dec(&m->nwaiters);
+
success:
-#ifdef DEBUG_MUTEX
- m->owner = tid;
-#endif
ret = 0;
out:
-#ifdef DEBUG_MUTEX
- if (ret < 0)
- printf("mutex failed (%s, tid = %d)\n", PAL_STRERROR(ret), tid);
-#endif
return ret;
}
int _DkMutexLock (struct mutex_handle * m)
{
int ret = 0, i;
-#ifdef DEBUG_MUTEX
- int tid = INLINE_SYSCALL(gettid, 0);
-#endif
+ return _DkMutexLockTimeout(m, -1);
+}
- /* Spin and try to take lock */
- for (i = 0; i < MUTEX_SPINLOCK_TIMES; i++) {
- if (!xchg(&m->b.locked, 1))
- goto success;
- cpu_relax();
- }
-
- // Mutex is union of u8 array and u32; this assumes a little-endian machine.
- while (xchg(&m->u, 257) & 1) {
- // This is broken. The mutex is in enclave memory, the URTS can't
- // do FUTEX_WAIT on it. This call will always fail and the next level
- // up needs to retry.
- ret = ocall_futex((int *) m, FUTEX_WAIT, 257, NULL);
- if (ret < 0 &&
- ret != -PAL_ERROR_TRYAGAIN) {
-#ifdef DEBUG_MUTEX
- printf("futex failed (err = %d)\n", ERRNO(ret));
-#endif
- goto out;
- }
- }
-
-success:
-#ifdef DEBUG_MUTEX
- m->owner = tid;
-#endif
- ret = 0;
-out:
-#ifdef DEBUG_MUTEX
- if (ret < 0)
- printf("mutex failed (%s, tid = %d)\n", PAL_STRERROR(ret), tid);
-#endif
- return ret;
+int _DkMutexAcquireTimeout (PAL_HANDLE handle, int _timeout)
+{
+ struct mutex_handle * mut = &handle->mutex.mut;
+ return _DkMutexLockTimeout(mut, _timeout);
}
int _DkMutexUnlock (struct mutex_handle * m)
{
- int ret = 0, i;
+ int ret = 0;
+ int need_wake;
-#ifdef DEBUG_MUTEX
- m->owner = 0;
-#endif
+ /* Unlock */
+ m->locked = 0;
+ /* We need to make sure the write to locked is visible to lock-ers
+ * before we read the waiter count. */
+ mb();
- /* Unlock, and if not contended then exit. */
- if ((m->u == 1) && (cmpxchg(&m->u, 1, 0) == 1)) return 0;
- m->b.locked = 0;
- barrier();
+ need_wake= atomic_read(&m->nwaiters);
- /* See if somebody else takes the lock */
- for (i = 0; i < MUTEX_SPINLOCK_TIMES * 2; i++) {
- if (m->b.locked)
- goto success;
- cpu_relax();
- }
+ /* If we need to wake someone up... */
+ if (need_wake)
+ ocall_futex((int *) m, FUTEX_WAKE, 1, NULL);
- m->b.contended = 0;
-
- /* Nobody took it, we need to wake someone up */
- ocall_futex((int *) m, FUTEX_WAKE, 1, NULL);
-
-success:
- ret = 0;
-out:
return ret;
}
+
+void _DkMutexRelease (PAL_HANDLE handle)
+{
+ struct mutex_handle * mut = &handle->mutex.mut;
+ int ret = _DkMutexUnlock(mut);
+ if (ret < 0)
+ _DkRaiseFailure(ret);
+ return;
+}
+
diff --git a/Pal/src/host/Linux-SGX/db_object.c b/Pal/src/host/Linux-SGX/db_object.c
index 92dfad34..3181d209 100644
--- a/Pal/src/host/Linux-SGX/db_object.c
+++ b/Pal/src/host/Linux-SGX/db_object.c
@@ -36,7 +36,6 @@
#include
#include
#include
-#include
#define DEFAULT_QUANTUM 500
@@ -63,7 +62,7 @@ static int _DkObjectWaitOne (PAL_HANDLE handle, uint64_t timeout)
events |= POLLOUT;
if (events) {
- fds[nfds].fd = HANDLE_HDR(handle)->fds[i];
+ fds[nfds].fd = handle->generic.fds[i];
fds[nfds].events = events|POLLHUP|POLLERR;
fds[nfds].revents = 0;
off[nfds] = i;
@@ -167,8 +166,8 @@ int _DkObjectsWaitAny (int count, PAL_HANDLE * handleArray, uint64_t timeout,
!(HANDLE_HDR(hdl)->flags & ERROR(j)))
events |= POLLOUT;
- if (events && HANDLE_HDR(hdl)->fds[j] != PAL_IDX_POISON) {
- fds[nfds].fd = HANDLE_HDR(hdl)->fds[j];
+ if (events && hdl->generic.fds[j] != PAL_IDX_POISON) {
+ fds[nfds].fd = hdl->generic.fds[j];
fds[nfds].events = events|POLLHUP|POLLERR;
fds[nfds].revents = 0;
hdls[nfds] = hdl;
@@ -205,7 +204,7 @@ int _DkObjectsWaitAny (int count, PAL_HANDLE * handleArray, uint64_t timeout,
for (j = 0 ; j < MAX_FDS ; j++)
if ((HANDLE_HDR(hdl)->flags & (RFD(j)|WFD(j))) &&
- HANDLE_HDR(hdl)->fds[j] == fds[i].fd)
+ hdl->generic.fds[j] == fds[i].fd)
break;
if (j == MAX_FDS)
diff --git a/Pal/src/host/Linux-SGX/db_pipes.c b/Pal/src/host/Linux-SGX/db_pipes.c
index 0b96ad23..26078ef5 100644
--- a/Pal/src/host/Linux-SGX/db_pipes.c
+++ b/Pal/src/host/Linux-SGX/db_pipes.c
@@ -324,12 +324,12 @@ static int pipe_delete (PAL_HANDLE handle, int access)
static int pipe_attrquerybyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr)
{
- if (HANDLE_HDR(handle)->fds[0] == PAL_IDX_POISON)
+ if (handle->generic.fds[0] == PAL_IDX_POISON)
return -PAL_ERROR_BADHANDLE;
attr->handle_type = PAL_GET_TYPE(handle);
- int read_fd = HANDLE_HDR(handle)->fds[0];
+ int read_fd = handle->generic.fds[0];
int flags = HANDLE_HDR(handle)->flags;
if (!IS_HANDLE_TYPE(handle, pipesrv)) {
@@ -350,6 +350,7 @@ static int pipe_attrquerybyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr)
int ret = ocall_poll(&pfd, 1, &waittime);
if (ret < 0)
return ret;
+
attr->readable = (ret == 1 && pfd.revents == POLLIN);
attr->disconnected = flags & ERROR(0);
@@ -361,7 +362,7 @@ static int pipe_attrquerybyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr)
static int pipe_attrsetbyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr)
{
- if (HANDLE_HDR(handle)->fds[0] == PAL_IDX_POISON)
+ if (handle->generic.fds[0] == PAL_IDX_POISON)
return -PAL_ERROR_BADHANDLE;
PAL_BOL * nonblocking = (HANDLE_HDR(handle)->type == pal_type_pipeprv) ?
@@ -369,7 +370,7 @@ static int pipe_attrsetbyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr)
&handle->pipe.nonblocking;
if (attr->nonblocking != *nonblocking) {
- int ret = ocall_fsetnonblock(HANDLE_HDR(handle)->fds[0], attr->nonblocking);
+ int ret = ocall_fsetnonblock(handle->generic.fds[0], attr->nonblocking);
if (ret < 0)
return ret;
diff --git a/Pal/src/host/Linux-SGX/db_semaphore.c b/Pal/src/host/Linux-SGX/db_semaphore.c
deleted file mode 100644
index d8ea59aa..00000000
--- a/Pal/src/host/Linux-SGX/db_semaphore.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
-/* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
-
-/* Copyright (C) 2014 OSCAR lab, Stony Brook University
- This file is part of Graphene Library OS.
-
- Graphene Library OS is free software: you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- Graphene Library OS is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see . */
-
-/*
- * db_semaphore.c
- *
- * This file contains APIs that provides operations of semaphores.
- */
-
-#include "pal_defs.h"
-#include "pal_linux_defs.h"
-#include "pal.h"
-#include "pal_internal.h"
-#include "pal_linux.h"
-#include "pal_error.h"
-#include "api.h"
-
-#include
-#include
-#include
-#include
-#include
-
-static inline int atomic_dec_if_positive (struct atomic_int *v)
-{
- int c, old, dec;
- c = atomic_read(v);
- for (;;) {
- dec = c - 1;
- if (dec < 0)
- break;
- old = atomic_cmpxchg((v), c, dec);
- if (old == c)
- break;
- c = old;
- }
- return dec;
-}
-
-int
-_DkSemaphoreCreate (PAL_HANDLE handle, int initialCount, int maxCount)
-{
- /*
- * 1. Allocate memory for db_sem (this includes a futex variable).
- * 2. Pack it into a PAL_HANDLE
- * 3. Set the semaphore object with the argument values (count, maxCount)
- */
-
- SET_HANDLE_TYPE(handle, semaphore);
- atomic_set(&handle->semaphore.nwaiters, 0);
- handle->semaphore.max_value = maxCount;
-
- /* optimization: if maxCount == 1, we make it into mutex */
- if (handle->semaphore.max_value == 1) {
- handle->semaphore.value.mut.u = initialCount;
- } else {
- atomic_set(&handle->semaphore.value.i, maxCount - initialCount);
- }
-
- return 0;
-}
-
-void _DkSemaphoreDestroy (PAL_HANDLE semaphoreHandle)
-{
- /* do nothing */
-}
-
-int _DkMutexLockTimeout (struct mutex_handle * mut, int timeout);
-
-int _DkSemaphoreAcquire (PAL_HANDLE sem, int count)
-{
- /* optimization: use it as a mutex */
- if (sem->semaphore.max_value == 1) {
- struct mutex_handle * mut = &sem->semaphore.value.mut;
- return _DkMutexLock(mut);
- }
-
- if (count > sem->semaphore.max_value)
- return -PAL_ERROR_INVAL;
-
- struct atomic_int * value = &sem->semaphore.value.i;
- int c = 0;
-
- if (!value)
- return -PAL_ERROR_BADHANDLE;
-
- if (count == 1)
- c = atomic_dec_and_test_nonnegative (value);
- else
- c = atomic_sub_and_test_nonnegative (count, value);
-
- if (c)
- return 0;
-
- /* We didn't get the lock. Bump the count back up. */
- if (count == 1)
- atomic_inc (value);
- else
- atomic_add (count, value);
-
- int ret = 0;
- atomic_inc (&sem->semaphore.nwaiters);
-
- while (1) {
- ret = ocall_futex((int *) &value->counter, FUTEX_WAIT, 0, NULL);
-
- if (ret < 0) {
- if (ret == -PAL_ERROR_TRYAGAIN)
- ret = 0;
- else
- break;
- }
-
- if (count == 1)
- c = atomic_dec_and_test_nonnegative (value);
- else
- c = atomic_sub_and_test_nonnegative (count, value);
-
- if (c)
- break;
-
- /* We didn't get the lock. Bump the count back up. */
- if (count == 1)
- atomic_inc (value);
- else
- atomic_add (count, value);
- }
-
- atomic_dec (&sem->semaphore.nwaiters);
- return ret;
-}
-
-int _DkSemaphoreAcquireTimeout (PAL_HANDLE sem, int count, uint64_t timeout)
-{
- /* Pass it up to the no-timeout version if no timeout requested */
- if (timeout == -1)
- return _DkSemaphoreAcquire(sem, count);
-
- /* optimization: use it as a mutex */
- if (sem->semaphore.max_value == 1) {
- struct mutex_handle * mut = & sem->semaphore.value.mut;
- return _DkMutexLockTimeout(mut, timeout);
- }
-
- if (count > sem->semaphore.max_value)
- return -PAL_ERROR_INVAL;
-
- struct atomic_int * value = &sem->semaphore.value.i;
- int c = 0;
-
- if (!value)
- return -PAL_ERROR_BADHANDLE;
-
- if (count == 1)
- c = atomic_dec_and_test_nonnegative (value);
- else
- c = atomic_sub_and_test_nonnegative (count, value);
-
- if (c)
- return 0;
-
- /* We didn't get the lock. Bump the count back up. */
- if (count == 1)
- atomic_inc ((struct atomic_int *) value);
- else
- atomic_add (count, (struct atomic_int *) value);
-
- if (!timeout)
- return -PAL_ERROR_TRYAGAIN;
-
- unsigned long waittime = timeout;
- int ret = 0;
-
- atomic_inc (&sem->semaphore.nwaiters);
-
- while (1) {
- ret = ocall_futex((int *) &value->counter, FUTEX_WAIT, 0, timeout >= 0 ? &waittime : NULL);
-
- if (ret < 0) {
- if (ret == -PAL_ERROR_TRYAGAIN)
- ret = 0;
- else
- break;
- }
-
- if (count == 1)
- c = atomic_dec_and_test_nonnegative (value);
- else
- c = atomic_sub_and_test_nonnegative (count, value);
-
- if (c)
- break;
- }
-
- /* We didn't get the lock. Bump the count back up. */
- if (count == 1)
- atomic_inc (value);
- else
- atomic_add (count, value);
-
- atomic_dec (&sem->semaphore.nwaiters);
- return ret;
-}
-
-void _DkSemaphoreRelease (PAL_HANDLE sem, int count)
-{
- /* optimization: use it as a mutex */
- if (sem->semaphore.max_value == 1) {
- struct mutex_handle * mut =
- &sem->semaphore.value.mut;
-
- int ret = _DkMutexUnlock(mut);
- if (ret < 0)
- _DkRaiseFailure(ret);
- return;
- }
-
- struct atomic_int * value = &sem->semaphore.value.i;
-
- if (count == 1)
- atomic_inc (value);
- else
- atomic_add (count, value);
-
- int nwaiters = atomic_read (&sem->semaphore.nwaiters);
- if (nwaiters > 0)
- ocall_futex((int *) &value->counter, FUTEX_WAKE, nwaiters, NULL);
-}
-
-int _DkSemaphoreGetCurrentCount (PAL_HANDLE sem)
-{
- if (sem->semaphore.max_value == 1) {
- struct mutex_handle * m = &sem->semaphore.value.mut;
- return m->b.locked;
- }
-
- int c = atomic_read(&sem->semaphore.value.i);
- return sem->semaphore.max_value - c;
-}
diff --git a/Pal/src/host/Linux-SGX/db_sockets.c b/Pal/src/host/Linux-SGX/db_sockets.c
index dc5bd0f3..e2cd2026 100644
--- a/Pal/src/host/Linux-SGX/db_sockets.c
+++ b/Pal/src/host/Linux-SGX/db_sockets.c
@@ -239,8 +239,8 @@ PAL_HANDLE socket_create_handle (int type, int fd, int options,
if (!hdl)
return NULL;
- memset(hdl, 0, sizeof(union pal_handle));
- HANDLE_TYPE(hdl) = type;
+ memset(hdl, 0, sizeof(struct pal_handle));
+ init_handle_hdr(HANDLE_HDR(hdl), type);
HANDLE_HDR(hdl)->flags |= RFD(0)|(type != pal_type_tcpsrv ? WFD(0) : 0);
hdl->sock.fd = fd;
void * addr = (void *) hdl + HANDLE_SIZE(sock);
diff --git a/Pal/src/host/Linux-SGX/db_streams.c b/Pal/src/host/Linux-SGX/db_streams.c
index 8ae81669..9a2a8594 100644
--- a/Pal/src/host/Linux-SGX/db_streams.c
+++ b/Pal/src/host/Linux-SGX/db_streams.c
@@ -292,7 +292,7 @@ int _DkSendHandle (PAL_HANDLE hdl, PAL_HANDLE cargo)
for (int i = 0 ; i < MAX_FDS ; i++)
if (HANDLE_HDR(cargo)->flags & (RFD(i)|WFD(1))) {
hdl_hdr.fds |= 1U << i;
- fds[nfds++] = HANDLE_HDR(cargo)->fds[i];
+ fds[nfds++] = cargo->generic.fds[i];
}
// ~ Initialize common parameter formessage passing
@@ -365,7 +365,7 @@ int _DkReceiveHandle(PAL_HANDLE hdl, PAL_HANDLE * cargo)
for (int i = 0 ; i < MAX_FDS ; i++)
if (hdl_hdr.fds & (1U << i)) {
if (n < nfds) {
- HANDLE_HDR(handle)->fds[i] = fds[n++];
+ handle->generic.fds[i] = fds[n++];
} else {
HANDLE_HDR(handle)->flags &= ~(RFD(i)|WFD(i));
}
diff --git a/Pal/src/host/Linux-SGX/enclave_framework.c b/Pal/src/host/Linux-SGX/enclave_framework.c
index 8e6a7133..de14fefb 100644
--- a/Pal/src/host/Linux-SGX/enclave_framework.c
+++ b/Pal/src/host/Linux-SGX/enclave_framework.c
@@ -127,7 +127,7 @@ int load_trusted_file (PAL_HANDLE file, sgx_stub_t ** stubptr,
struct trusted_file * tf = NULL, * tmp;
char uri[URI_MAX];
char normpath[URI_MAX];
- int ret, fd = HANDLE_HDR(file)->fds[0], uri_len, len;
+ int ret, fd = file->file.fd, uri_len, len;
if (!(HANDLE_HDR(file)->flags & RFD(0)))
return -PAL_ERROR_DENIED;
diff --git a/Pal/src/host/Linux-SGX/pal.map b/Pal/src/host/Linux-SGX/pal.map
index 1cca6f4c..1627a023 100644
--- a/Pal/src/host/Linux-SGX/pal.map
+++ b/Pal/src/host/Linux-SGX/pal.map
@@ -5,9 +5,9 @@ PAL {
DkThreadCreate; DkThreadDelayExecution;
DkThreadYieldExecution; DkThreadExit; DkThreadResume;
- DkSemaphoreCreate; DkNotificationEventCreate;
+ DkMutexCreate; DkNotificationEventCreate;
DkSynchronizationEventCreate;
- DkSemaphoreRelease;
+ DkMutexRelease;
DkEventSet; DkEventClear;
DkObjectsWaitAny;
diff --git a/Pal/src/host/Linux-SGX/pal_host.h b/Pal/src/host/Linux-SGX/pal_host.h
index dd1051f3..fbc5dc63 100644
--- a/Pal/src/host/Linux-SGX/pal_host.h
+++ b/Pal/src/host/Linux-SGX/pal_host.h
@@ -49,22 +49,25 @@ void free_untrusted (void * mem);
#include
-/* internal Mutex design, the structure has to align at integer boundary
- because it is required by futex call. If DEBUG_MUTEX is defined,
- mutex_handle will record the owner of mutex locking. */
+/* Simpler mutex design: a single variable that tracks whether the mutex
+ * is locked (just waste a 64 bit word for now). State is 1 (locked) or
+ * 0 (unlocked).
+ *
+ * Keep a count of how many threads are waiting on the mutex.
+ *
+ * If DEBUG_MUTEX is defined, mutex_handle will record the owner of
+ * mutex locking. */
struct mutex_handle {
- union {
- unsigned int u;
- struct {
- unsigned char locked;
- unsigned char contended;
- } b;
- };
+ volatile int64_t locked;
+ struct atomic_int nwaiters;
+#ifdef DEBUG_MUTEX
+ int owner;
+#endif
};
/* Initializer of Mutexes */
#define MUTEX_HANDLE_INIT { .u = 0 }
-#define INIT_MUTEX_HANDLE(m) do { m->u = 0; } while (0)
+#define INIT_MUTEX_HANDLE(m) do { (m)->u = 0; } while (0)
DEFINE_LIST(pal_handle_thread);
struct pal_handle_thread {
@@ -75,117 +78,104 @@ struct pal_handle_thread {
void * param;
};
-typedef union pal_handle
+typedef struct pal_handle
{
- /* TSAI: Here we define the internal types of PAL_HANDLE
- * in PAL design, user has not to access the content inside the
- * handle, also there is no need to allocate the internal
- * handles, so we hide the type name of these handles on purpose.
+ /*
+ * Here we define the internal structure of PAL_HANDLE.
+ * user has no access to the content inside these handles.
*/
- struct {
- PAL_IDX type;
- PAL_REF ref;
- PAL_FLG flags;
- PAL_IDX fds[];
- } hdr;
+ PAL_HDR hdr;
+ union {
+ struct {
+ PAL_IDX fds[2];
+ } generic;
- struct {
- PAL_HDR reserved;
- PAL_IDX fd;
- PAL_BOL append;
- PAL_BOL pass;
- PAL_STR realpath;
- PAL_NUM total;
- PAL_PTR stubs;
- } file;
+ struct {
+ PAL_IDX fd;
+ PAL_BOL append;
+ PAL_BOL pass;
+ PAL_STR realpath;
+ PAL_NUM total;
+ PAL_PTR stubs;
+ } file;
- struct {
- PAL_HDR reserved;
- PAL_IDX fd;
- PAL_NUM pipeid;
- PAL_BOL nonblocking;
- } pipe;
+ struct {
+ PAL_IDX fd;
+ PAL_NUM pipeid;
+ PAL_BOL nonblocking;
+ } pipe;
- struct {
- PAL_HDR reserved;
- PAL_IDX fds[2];
- PAL_BOL nonblocking;
- } pipeprv;
+ struct {
+ PAL_IDX fds[2];
+ PAL_BOL nonblocking;
+ } pipeprv;
- struct {
- PAL_HDR reserved;
- PAL_IDX fd_in, fd_out;
- PAL_IDX dev_type;
- PAL_BOL destroy;
- PAL_STR realpath;
- } dev;
+ struct {
+ PAL_IDX fd_in, fd_out;
+ PAL_IDX dev_type;
+ PAL_BOL destroy;
+ PAL_STR realpath;
+ } dev;
- struct {
- PAL_HDR reserved;
- PAL_IDX fd;
- PAL_STR realpath;
- PAL_PTR buf;
- PAL_PTR ptr;
- PAL_PTR end;
- PAL_BOL endofstream;
- } dir;
+ struct {
+ PAL_IDX fd;
+ PAL_STR realpath;
+ PAL_PTR buf;
+ PAL_PTR ptr;
+ PAL_PTR end;
+ PAL_BOL endofstream;
+ } dir;
- struct {
- PAL_HDR reserved;
- PAL_IDX fd;
- } gipc;
+ struct {
+ PAL_IDX fd;
+ } gipc;
- struct {
- PAL_HDR reserved;
- PAL_IDX fd;
- PAL_PTR bind;
- PAL_PTR conn;
- PAL_BOL nonblocking;
- PAL_NUM linger;
- PAL_NUM receivebuf;
- PAL_NUM sendbuf;
- PAL_NUM receivetimeout;
- PAL_NUM sendtimeout;
- PAL_BOL tcp_cork;
- PAL_BOL tcp_keepalive;
- PAL_BOL tcp_nodelay;
- } sock;
+ struct {
+ PAL_IDX fd;
+ PAL_PTR bind;
+ PAL_PTR conn;
+ PAL_BOL nonblocking;
+ PAL_NUM linger;
+ PAL_NUM receivebuf;
+ PAL_NUM sendbuf;
+ PAL_NUM receivetimeout;
+ PAL_NUM sendtimeout;
+ PAL_BOL tcp_cork;
+ PAL_BOL tcp_keepalive;
+ PAL_BOL tcp_nodelay;
+ } sock;
- struct {
- PAL_HDR reserved;
- PAL_IDX stream_in, stream_out;
- PAL_IDX cargo;
- PAL_IDX pid;
- PAL_BOL nonblocking;
- } process;
+ struct {
+ PAL_IDX stream_in, stream_out;
+ PAL_IDX cargo;
+ PAL_IDX pid;
+ PAL_BOL nonblocking;
+ } process;
- struct {
- PAL_HDR reserved;
- PAL_IDX cli;
- PAL_IDX srv;
- PAL_IDX port;
- PAL_BOL nonblocking;
- } mcast;
+ struct {
+ PAL_IDX cli;
+ PAL_IDX srv;
+ PAL_IDX port;
+ PAL_BOL nonblocking;
+ } mcast;
- struct pal_handle_thread thread;
+ struct pal_handle_thread thread;
- struct {
- PAL_HDR reserved;
- struct atomic_int nwaiters;
- PAL_NUM max_value;
- union {
- struct mutex_handle mut;
- struct atomic_int i;
- } value;
- } semaphore;
+ struct {
+ struct atomic_int nwaiters;
+ PAL_NUM max_value;
+ union {
+ struct mutex_handle mut;
+ } mutex;
- struct {
- PAL_HDR reserved;
- struct atomic_int signaled;
- struct atomic_int nwaiters;
- PAL_BOL isnotification;
- } event;
+ struct {
+ struct atomic_int signaled;
+ struct atomic_int nwaiters;
+ PAL_BOL isnotification;
+ } event;
+ };
+ };
} * PAL_HANDLE;
#define RFD(n) (00001 << (n))
diff --git a/Pal/src/host/Linux-SGX/pal_linux.h b/Pal/src/host/Linux-SGX/pal_linux.h
index 63ddc15b..0dc0d507 100644
--- a/Pal/src/host/Linux-SGX/pal_linux.h
+++ b/Pal/src/host/Linux-SGX/pal_linux.h
@@ -31,6 +31,15 @@
#include "sgx_api.h"
#include "enclave_ocalls.h"
+#ifdef __x86_64__
+# include "sysdep-x86_64.h"
+#endif
+
+#define IS_ERR INTERNAL_SYSCALL_ERROR
+#define IS_ERR_P INTERNAL_SYSCALL_ERROR_P
+#define ERRNO INTERNAL_SYSCALL_ERRNO
+#define ERRNO_P INTERNAL_SYSCALL_ERRNO_P
+
extern struct pal_linux_state {
PAL_NUM parent_process_id;
PAL_NUM process_id;
@@ -75,11 +84,11 @@ bool stataccess (struct stat * stats, int acc);
#ifdef IN_ENCLAVE
/* Locking and unlocking of Mutexes */
-int _DkMutexCreate (struct mutex_handle * mut);
+int __DkMutexCreate (struct mutex_handle * mut);
int _DkMutexAtomicCreate (struct mutex_handle * mut);
-int _DkMutexDestroy (struct mutex_handle * mut);
+int __DkMutexDestroy (struct mutex_handle * mut);
int _DkMutexLock (struct mutex_handle * mut);
-int _DkMutexLockTimeout (struct mutex_handle * mut, int timeout);
+int _DkMutexLockTimeout (struct mutex_handle * mut, uint64_t timeout);
int _DkMutexUnlock (struct mutex_handle * mut);
int * get_futex (void);
@@ -213,15 +222,4 @@ int pal_printf(const char * fmt, ...);
do { if ((class) & DBG_LEVEL) pal_printf(fmt); } while (0)
#endif
-#ifdef __i386__
-# define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
-# define cpu_relax() asm volatile("rep; nop" ::: "memory");
-#endif
-
-#ifdef __x86_64__
-# include
-# define rmb() asm volatile("lfence" ::: "memory")
-# define cpu_relax() asm volatile("rep; nop" ::: "memory");
-#endif
-
#endif /* PAL_LINUX_H */
diff --git a/Pal/src/host/Linux/Makefile b/Pal/src/host/Linux/Makefile
index 9cb87d28..16ffc0ec 100644
--- a/Pal/src/host/Linux/Makefile
+++ b/Pal/src/host/Linux/Makefile
@@ -13,7 +13,7 @@ host_files = libpal-Linux.a
defs = -DIN_PAL -DPAL_DIR=$(PAL_DIR) -DRUNTIME_DIR=$(RUNTIME_DIR)
objs = $(addprefix db_,files devices pipes sockets streams memory threading \
- semaphore mutex events process object main rtld misc ipc \
+ mutex events process object main rtld misc ipc \
exception) manifest clone-x86_64 gettimeofday-x86_64
graphene_lib = ../../.lib/graphene-lib.a
headers = $(wildcard *.h) $(wildcard ../../*.h) $(wildcard ../../../lib/*.h)
diff --git a/Pal/src/host/Linux/db_devices.c b/Pal/src/host/Linux/db_devices.c
index 47dfd9f3..6ce59d65 100644
--- a/Pal/src/host/Linux/db_devices.c
+++ b/Pal/src/host/Linux/db_devices.c
@@ -231,6 +231,7 @@ static int dev_open (PAL_HANDLE * handle, const char * type, const char * uri,
return -PAL_ERROR_NOTSUPPORT;
PAL_HANDLE hdl = malloc(HANDLE_SIZE(dev));
+ SET_HANDLE_TYPE(hdl, dev);
hdl->dev.fd_in = PAL_IDX_POISON;
hdl->dev.fd_out = PAL_IDX_POISON;
*handle = hdl;
diff --git a/Pal/src/host/Linux/db_files.c b/Pal/src/host/Linux/db_files.c
index 0b2304c4..197a6799 100644
--- a/Pal/src/host/Linux/db_files.c
+++ b/Pal/src/host/Linux/db_files.c
@@ -241,7 +241,7 @@ static int file_attrquery (const char * type, const char * uri,
static int file_attrquerybyhdl (PAL_HANDLE handle,
PAL_STREAM_ATTR * attr)
{
- int fd = HANDLE_HDR(handle)->fds[0];
+ int fd = handle->generic.fds[0];
struct stat stat_buf;
int ret = INLINE_SYSCALL(fstat, 2, fd, &stat_buf);
@@ -256,7 +256,7 @@ static int file_attrquerybyhdl (PAL_HANDLE handle,
static int file_attrsetbyhdl (PAL_HANDLE handle,
PAL_STREAM_ATTR * attr)
{
- int fd = HANDLE_HDR(handle)->fds[0], ret;
+ int fd = handle->generic.fds[0], ret;
ret = INLINE_SYSCALL(fchmod, 2, fd, attr->share_flags | 0600);
if (IS_ERR(ret))
diff --git a/Pal/src/host/Linux/db_mutex.c b/Pal/src/host/Linux/db_mutex.c
index 4ac1255c..8b96196d 100644
--- a/Pal/src/host/Linux/db_mutex.c
+++ b/Pal/src/host/Linux/db_mutex.c
@@ -36,73 +36,128 @@
#include
#include
#include
-#include
#include
#include
#include
-#ifdef __i386__
-# define barrier() asm volatile("" ::: "memory");
-# define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
-# define cpu_relax() asm volatile("rep; nop" ::: "memory");
-#endif
-
#ifdef __x86_64__
# include
-# define barrier() asm volatile("" ::: "memory");
-# define rmb() asm volatile("lfence" ::: "memory")
-# define cpu_relax() asm volatile("rep; nop" ::: "memory");
#endif
#define MUTEX_SPINLOCK_TIMES 100
+#define MUTEX_UNLOCKED 0
+#define MUTEX_LOCKED 1
+
+/* Interplay between locked and nwaiters:
+ *
+ * If lock is unlocked and uncontended, just set the locked state.
+ *
+ * Important possible interleavings of lock and unlock:
+ *
+ * Case 1:
+ *
+ * Owner: Locker:
+ * Try lock and fail; increment nwaiters; sleep
+ * Set state to unlocked
+ * Read nwaiters; wake
+ * Try again and succeed.
+ *
+ * ***************************************************
+ *
+ * Case 2:
+ *
+ * Owner: Locker:
+ * Try lock and fail
+ * Set state to unlocked
+ * Read nwaiters (=0)
+ * Increment nwaiters.
+ * Can't go to sleep here; will cmpxchg locked and succeed
+ * Don't wake anyone
+ */
+
+int
+_DkMutexCreate (PAL_HANDLE handle, int initialCount)
+{
+ /*
+ * Allocation and free of the handle are done outside of host-specific code.
+ * This code initializes the mutex state that is host-specific,
+ * including how initialCount is encoded.
+ */
+ atomic_set(&handle->mutex.mut.nwaiters, 0);
+ handle->mutex.mut.locked = initialCount;
+ return 0;
+}
+
+void _DkMutexDestroy (PAL_HANDLE handle)
+{
+ // Do nothing; handled in higher-level code
+}
+
int _DkMutexLockTimeout (struct mutex_handle * m, uint64_t timeout)
{
- int ret = 0;
+ int i, ret = 0;
#ifdef DEBUG_MUTEX
int tid = INLINE_SYSCALL(gettid, 0);
#endif
+ /* If this is a trylock-style call, break more quickly. */
+ int iterations = (timeout == 0) ? 1 : MUTEX_SPINLOCK_TIMES;
- if (timeout == -1)
- return -_DkMutexLock(m);
-
- if (!xchg(&m->b.locked, 1))
- goto success;
+ /* Spin and try to take lock. Ignore any contribution this makes toward
+ * the timeout.*/
+ for (i = 0; i < iterations; i++) {
+ if (MUTEX_UNLOCKED == cmpxchg(&m->locked, MUTEX_UNLOCKED, MUTEX_LOCKED))
+ goto success;
+ cpu_relax();
+ }
if (timeout == 0) {
ret = -PAL_ERROR_TRYAGAIN;
goto out;
}
- while (xchg(&m->u, 257) & 1) {
- struct timespec waittime;
- long sec = timeout / 1000000;
- long microsec = timeout - (sec * 1000000);
- waittime.tv_sec = sec;
- waittime.tv_nsec = microsec * 1000;
+ // Bump up the waiters count; we are probably going to block
+ atomic_inc(&m->nwaiters);
- ret = INLINE_SYSCALL(futex, 6, m, FUTEX_WAIT, 257, &waittime, NULL, 0);
+ while (MUTEX_LOCKED == cmpxchg(&m->locked, MUTEX_UNLOCKED, MUTEX_LOCKED)) {
+ struct timespec waittime, *waittimep = NULL;
+ if (timeout != NO_TIMEOUT) {
+ long sec = timeout / 1000000;
+ long microsec = timeout - (sec * 1000000);
+ waittime.tv_sec = sec;
+ waittime.tv_nsec = microsec * 1000;
+ waittimep = &waittime;
+ }
+
+ ret = INLINE_SYSCALL(futex, 6, m, FUTEX_WAIT, MUTEX_LOCKED, waittimep, NULL, 0);
if (IS_ERR(ret)) {
if (ERRNO(ret) == EWOULDBLOCK) {
- xchg(&m->b.contended, 0);
- ret = -PAL_ERROR_TRYAGAIN;
+ if (timeout != NO_TIMEOUT) {
+ ret = -PAL_ERROR_TRYAGAIN;
+ atomic_dec(&m->nwaiters);
+ goto out;
+ }
+ } else {
+#ifdef DEBUG_MUTEX
+ printf("futex failed (err = %d)\n", ERRNO(ret));
+#endif
+ ret = unix_to_pal_error(ERRNO(ret));
+ atomic_dec(&m->nwaiters);
goto out;
}
-#ifdef DEBUG_MUTEX
- printf("futex failed (err = %d)\n", ERRNO(ret));
-#endif
- ret = unix_to_pal_error(ERRNO(ret));
- goto out;
}
}
+ atomic_dec(&m->nwaiters);
+
success:
#ifdef DEBUG_MUTEX
m->owner = tid;
#endif
ret = 0;
out:
+
#ifdef DEBUG_MUTEX
if (ret < 0)
printf("mutex failed (%s, tid = %d)\n", PAL_STRERROR(ret), tid);
@@ -112,71 +167,40 @@ out:
int _DkMutexLock (struct mutex_handle * m)
{
- int ret = 0, i;
-#ifdef DEBUG_MUTEX
- int tid = INLINE_SYSCALL(gettid, 0);
-#endif
+ return _DkMutexLockTimeout(m, -1);
+}
- /* Spin and try to take lock */
- for (i = 0; i < MUTEX_SPINLOCK_TIMES; i++) {
- if (!xchg(&m->b.locked, 1))
- goto success;
- cpu_relax();
- }
-
- while (xchg(&m->u, 257) & 1) {
- ret = INLINE_SYSCALL(futex, 6, m, FUTEX_WAIT, 257, NULL, NULL, 0);
-
- if (IS_ERR(ret) &&
- ERRNO(ret) != EWOULDBLOCK) {
-#ifdef DEBUG_MUTEX
- printf("futex failed (err = %d)\n", ERRNO(ret));
-#endif
- ret = unix_to_pal_error(ERRNO(ret));
- goto out;
- }
- }
-
-success:
-#ifdef DEBUG_MUTEX
- m->owner = tid;
-#endif
- ret = 0;
-out:
-#ifdef DEBUG_MUTEX
- if (ret < 0)
- printf("mutex failed (%s, tid = %d)\n", PAL_STRERROR(ret), tid);
-#endif
- return ret;
+int _DkMutexAcquireTimeout (PAL_HANDLE handle, int timeout)
+{
+ return _DkMutexLockTimeout(&handle->mutex.mut, timeout);
}
int _DkMutexUnlock (struct mutex_handle * m)
{
- int ret = 0, i;
+ int ret = 0;
+ int need_wake;
#ifdef DEBUG_MUTEX
m->owner = 0;
#endif
- /* Unlock, and if not contended then exit. */
- if ((m->u == 1) && (cmpxchg(&m->u, 1, 0) == 1)) return 0;
- m->b.locked = 0;
- barrier();
+ /* Unlock */
+ m->locked = 0;
+ /* We need to make sure the write to locked is visible to lock-ers
+ * before we read the waiter count. */
+ mb();
- /* Spin and try to take lock */
- for (i = 0; i < MUTEX_SPINLOCK_TIMES * 2; i++) {
- if (m->b.locked)
- goto success;
- cpu_relax();
- }
+ need_wake = atomic_read(&m->nwaiters);
- m->b.contended = 0;
+ /* If we need to wake someone up... */
+ if (need_wake)
+ INLINE_SYSCALL(futex, 6, m, FUTEX_WAKE, 1, NULL, NULL, 0);
- /* We need to wake someone up */
- INLINE_SYSCALL(futex, 6, m, FUTEX_WAKE, 1, NULL, NULL, 0);
-
-success:
- ret = 0;
-out:
return ret;
}
+
+void _DkMutexRelease (PAL_HANDLE handle)
+{
+ _DkMutexUnlock(&handle->mutex.mut);
+ return;
+}
diff --git a/Pal/src/host/Linux/db_object.c b/Pal/src/host/Linux/db_object.c
index c4498a75..aa41453b 100644
--- a/Pal/src/host/Linux/db_object.c
+++ b/Pal/src/host/Linux/db_object.c
@@ -36,7 +36,6 @@
#include
#include
#include
-#include
#include
#define DEFAULT_QUANTUM 500
@@ -77,7 +76,7 @@ static int _DkObjectWaitOne (PAL_HANDLE handle, uint64_t timeout)
events |= POLLOUT;
if (events) {
- fds[nfds].fd = HANDLE_HDR(handle)->fds[i];
+ fds[nfds].fd = handle->generic.fds[i];
fds[nfds].events = events|POLLHUP|POLLERR;
fds[nfds].revents = 0;
off[nfds] = i;
@@ -191,8 +190,8 @@ int _DkObjectsWaitAny (int count, PAL_HANDLE * handleArray, uint64_t timeout,
!(HANDLE_HDR(hdl)->flags & ERROR(j)))
events |= POLLOUT;
- if (events && HANDLE_HDR(hdl)->fds[j] != PAL_IDX_POISON) {
- fds[nfds].fd = HANDLE_HDR(hdl)->fds[j];
+ if (events && hdl->generic.fds[j] != PAL_IDX_POISON) {
+ fds[nfds].fd = hdl->generic.fds[j];
fds[nfds].events = events|POLLHUP|POLLERR;
fds[nfds].revents = 0;
hdls[nfds] = hdl;
@@ -246,7 +245,7 @@ int _DkObjectsWaitAny (int count, PAL_HANDLE * handleArray, uint64_t timeout,
for (j = 0 ; j < MAX_FDS ; j++)
if ((HANDLE_HDR(hdl)->flags & (RFD(j)|WFD(j))) &&
- HANDLE_HDR(hdl)->fds[j] == fds[i].fd)
+ hdl->generic.fds[j] == fds[i].fd)
break;
if (j == MAX_FDS)
diff --git a/Pal/src/host/Linux/db_pipes.c b/Pal/src/host/Linux/db_pipes.c
index 70c337df..0734dbd2 100644
--- a/Pal/src/host/Linux/db_pipes.c
+++ b/Pal/src/host/Linux/db_pipes.c
@@ -524,28 +524,29 @@ static int pipe_attrquerybyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr)
{
int ret, val;
- if (HANDLE_HDR(handle)->fds[0] == PAL_IDX_POISON)
+ if (handle->generic.fds[0] == PAL_IDX_POISON)
return -PAL_ERROR_BADHANDLE;
attr->handle_type = PAL_GET_TYPE(handle);
- int read_fd = HANDLE_HDR(handle)->fds[0];
- int flags = HANDLE_HDR(handle)->flags;
-
- if (!IS_HANDLE_TYPE(handle, pipesrv)) {
- ret = INLINE_SYSCALL(ioctl, 3, read_fd, FIONREAD, &val);
+ if (attr->handle_type != pal_type_pipesrv) {
+ ret = INLINE_SYSCALL(ioctl, 3, handle->generic.fds[0], FIONREAD, &val);
if (IS_ERR(ret)) {
return unix_to_pal_error(ERRNO(ret));
}
attr->pending_size = val;
- attr->writeable = flags & (
+ attr->writeable = HANDLE_HDR(handle)->flags & (
IS_HANDLE_TYPE(handle, pipeprv) ? WRITEABLE(1) : WRITEABLE(0));
} else {
+ struct pollfd pfd = { .fd = handle->generic.fds[0], .events = POLLIN, .revents = 0 };
+ struct timespec tp = { 0, 0 };
+ ret = INLINE_SYSCALL(ppoll, 5, &pfd, 1, &tp, NULL, 0);
+ attr->readable = (ret == 1 && pfd.revents == POLLIN);
attr->pending_size = 0;
attr->writeable = PAL_FALSE;
}
- struct pollfd pfd = { .fd = read_fd, .events = POLLIN, .revents = 0 };
+ struct pollfd pfd = { .fd = handle->generic.fds[0], .events = POLLIN, .revents = 0 };
struct timespec tp = { 0, 0 };
ret = INLINE_SYSCALL(ppoll, 5, &pfd, 1, &tp, NULL, 0);
attr->readable = (ret == 1 && pfd.revents == POLLIN);
@@ -558,7 +559,7 @@ static int pipe_attrquerybyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr)
static int pipe_attrsetbyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr)
{
- if (HANDLE_HDR(handle)->fds[0] == PAL_IDX_POISON)
+ if (handle->generic.fds[0] == PAL_IDX_POISON)
return -PAL_ERROR_BADHANDLE;
int ret;
@@ -567,7 +568,7 @@ static int pipe_attrsetbyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr)
&handle->pipe.nonblocking;
if (attr->nonblocking != *nonblocking) {
- ret = INLINE_SYSCALL(fcntl, 3, HANDLE_HDR(handle)->fds[0], F_SETFL,
+ ret = INLINE_SYSCALL(fcntl, 3, handle->generic.fds[0], F_SETFL,
attr->nonblocking ? O_NONBLOCK : 0);
if (IS_ERR(ret))
diff --git a/Pal/src/host/Linux/db_semaphore.c b/Pal/src/host/Linux/db_semaphore.c
deleted file mode 100644
index 25a0005f..00000000
--- a/Pal/src/host/Linux/db_semaphore.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
-/* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
-
-/* Copyright (C) 2014 OSCAR lab, Stony Brook University
- This file is part of Graphene Library OS.
-
- Graphene Library OS is free software: you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- Graphene Library OS is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see . */
-
-/*
- * db_semaphore.c
- *
- * This file contains APIs that provides operations of semaphores.
- */
-
-#include "pal_defs.h"
-#include "pal_linux_defs.h"
-#include "pal.h"
-#include "pal_internal.h"
-#include "pal_linux.h"
-#include "pal_error.h"
-#include "api.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-static inline int atomic_dec_if_positive (struct atomic_int *v)
-{
- int c, old, dec;
- c = atomic_read(v);
- for (;;) {
- dec = c - 1;
- if (unlikely(dec < 0))
- break;
- old = atomic_cmpxchg((v), c, dec);
- if (likely(old == c))
- break;
- c = old;
- }
- return dec;
-}
-
-int
-_DkSemaphoreCreate (PAL_HANDLE handle, int initialCount, int maxCount)
-{
- /*
- * 1. Allocate memory for db_sem (this includes a futex variable).
- * 2. Pack it into a PAL_HANDLE
- * 3. Set the semaphore object with the argument values (count, maxCount)
- */
-
- SET_HANDLE_TYPE(handle, semaphore);
- atomic_set(&handle->semaphore.nwaiters, 0);
- handle->semaphore.max_value = maxCount;
-
- /* optimization: if maxCount == 1, we make it into mutex */
- if (handle->semaphore.max_value == 1) {
- handle->semaphore.value.mut.u = initialCount;
- } else {
- atomic_set(&handle->semaphore.value.i, maxCount - initialCount);
- }
-
- return 0;
-}
-
-void _DkSemaphoreDestroy (PAL_HANDLE semaphoreHandle)
-{
- free(semaphoreHandle);
-}
-
-int _DkMutexLockTimeout (struct mutex_handle * mut, uint64_t timeout);
-
-int _DkSemaphoreAcquire (PAL_HANDLE sem, int count)
-{
- /* optimization: use it as a mutex */
- if (sem->semaphore.max_value == 1) {
- struct mutex_handle * mut = &sem->semaphore.value.mut;
- _DkMutexLock(mut);
- return 0;
- }
-
- if (count > sem->semaphore.max_value)
- return -PAL_ERROR_INVAL;
-
- struct atomic_int * value = &sem->semaphore.value.i;
- int c = 0;
-
- if (!value)
- return -PAL_ERROR_BADHANDLE;
-
- if (count == 1)
- c = atomic_dec_and_test_nonnegative (value);
- else
- c = atomic_sub_and_test_nonnegative (count, value);
-
- if (c)
- return 0;
-
- /* We didn't get the lock. Bump the count back up. */
- if (count == 1)
- atomic_inc (value);
- else
- atomic_add (count, value);
-
- int ret = 0;
- atomic_inc (&sem->semaphore.nwaiters);
-
- while (1) {
- ret = INLINE_SYSCALL(futex, 6, value, FUTEX_WAIT, 0,
- NULL, NULL, 0);
-
- if (IS_ERR(ret)) {
- if (ERRNO(ret) == EWOULDBLOCK) {
- ret = 0;
- } else {
- ret = unix_to_pal_error(ERRNO(ret));
- break;
- }
- }
-
- if (count == 1)
- c = atomic_dec_and_test_nonnegative (value);
- else
- c = atomic_sub_and_test_nonnegative (count, value);
-
- if (c)
- break;
-
- /* We didn't get the lock. Bump the count back up. */
- if (count == 1)
- atomic_inc (value);
- else
- atomic_add (count, value);
- }
-
- atomic_dec (&sem->semaphore.nwaiters);
- return ret;
-}
-
-int _DkSemaphoreAcquireTimeout (PAL_HANDLE sem, int count, uint64_t timeout)
-{
- /* Pass it up to the no-timeout version if no timeout requested */
- if (timeout == NO_TIMEOUT)
- return _DkSemaphoreAcquire(sem, count);
-
- /* optimization: use it as a mutex */
- if (sem->semaphore.max_value == 1) {
- struct mutex_handle * mut = & sem->semaphore.value.mut;
- return _DkMutexLockTimeout(mut, timeout);
- }
-
- if (count > sem->semaphore.max_value)
- return -PAL_ERROR_INVAL;
-
- struct atomic_int * value = &sem->semaphore.value.i;
- int c = 0;
-
- if (!value)
- return -PAL_ERROR_BADHANDLE;
-
- if (count == 1)
- c = atomic_dec_and_test_nonnegative (value);
- else
- c = atomic_sub_and_test_nonnegative (count, value);
-
- if (c)
- return 0;
-
- /* We didn't get the lock. Bump the count back up. */
- if (count == 1)
- atomic_inc (value);
- else
- atomic_add (count, value);
-
- if (!timeout)
- return -PAL_ERROR_TRYAGAIN;
-
- struct timespec waittime;
- long sec = timeout / 1000000;
- long microsec = timeout - (sec * 1000000);
- waittime.tv_sec = sec;
- waittime.tv_nsec = microsec * 1000;
- int ret = 0;
- atomic_inc (&sem->semaphore.nwaiters);
-
- while (1) {
- ret = INLINE_SYSCALL(futex, 6, value, FUTEX_WAIT, 0,
- &waittime, NULL, 0);
-
- if (ERRNO(ret) == EWOULDBLOCK) {
- ret = 0;
- } else {
- ret = unix_to_pal_error(ERRNO(ret));
- break;
- }
-
- if (count == 1)
- c = atomic_dec_and_test_nonnegative (value);
- else
- c = atomic_sub_and_test_nonnegative (count, value);
-
- if (c)
- break;
- }
-
- /* We didn't get the lock. Bump the count back up. */
- if (count == 1)
- atomic_inc (value);
- else
- atomic_add (count, value);
-
- atomic_dec (&sem->semaphore.nwaiters);
- return ret;
-}
-
-void _DkSemaphoreRelease (PAL_HANDLE sem, int count)
-{
- /* optimization: use it as a mutex */
- if (sem->semaphore.max_value == 1) {
- struct mutex_handle * mut =
- &sem->semaphore.value.mut;
-
- _DkMutexUnlock(mut);
- return;
- }
-
- struct atomic_int * value = &sem->semaphore.value.i;
-
- if (count == 1)
- atomic_inc (value);
- else
- atomic_add (count, value);
-
- int nwaiters = atomic_read (&sem->semaphore.nwaiters);
-
- if (nwaiters > 0)
- INLINE_SYSCALL(futex, 6, value, FUTEX_WAKE, nwaiters, NULL, NULL, 0);
-}
-
-int _DkSemaphoreGetCurrentCount (PAL_HANDLE sem)
-{
- if (sem->semaphore.max_value == 1) {
- struct mutex_handle * m = &sem->semaphore.value.mut;
- return m->b.locked;
- }
-
- int c = atomic_read(&sem->semaphore.value.i);
- return sem->semaphore.max_value - c;
-}
diff --git a/Pal/src/host/Linux/db_sockets.c b/Pal/src/host/Linux/db_sockets.c
index 00d55ef5..92fb7a1e 100644
--- a/Pal/src/host/Linux/db_sockets.c
+++ b/Pal/src/host/Linux/db_sockets.c
@@ -243,8 +243,8 @@ PAL_HANDLE socket_create_handle (int type, int fd, int options,
if (!hdl)
return NULL;
- memset(hdl, 0, sizeof(union pal_handle));
- PAL_GET_TYPE(hdl) = type;
+ memset(hdl, 0, sizeof(struct pal_handle));
+ init_handle_hdr(HANDLE_HDR(hdl), type);
HANDLE_HDR(hdl)->flags |= RFD(0)|(type != pal_type_tcpsrv ? WFD(0) : 0);
hdl->sock.fd = fd;
void * addr = (void *) hdl + HANDLE_SIZE(sock);
diff --git a/Pal/src/host/Linux/db_streams.c b/Pal/src/host/Linux/db_streams.c
index 54db3a1b..73680ac9 100644
--- a/Pal/src/host/Linux/db_streams.c
+++ b/Pal/src/host/Linux/db_streams.c
@@ -92,7 +92,7 @@ int handle_set_cloexec (PAL_HANDLE handle, bool enable)
if (HANDLE_HDR(handle)->flags & (RFD(i)|WFD(i))) {
long flags = enable ? FD_CLOEXEC : 0;
int ret = INLINE_SYSCALL(fcntl, 3,
- HANDLE_HDR(handle)->fds[i], F_SETFD,
+ handle->generic.fds[i], F_SETFD,
flags);
if (IS_ERR(ret) && ERRNO(ret) != EBADF)
return -PAL_ERROR_DENIED;
@@ -305,7 +305,7 @@ int _DkSendHandle (PAL_HANDLE hdl, PAL_HANDLE cargo)
for (int i = 0 ; i < MAX_FDS ; i++)
if (HANDLE_HDR(cargo)->flags & (RFD(i)|WFD(1))) {
hdl_hdr.fds |= 1U << i;
- fds[nfds++] = HANDLE_HDR(cargo)->fds[i];
+ fds[nfds++] = cargo->generic.fds[i];
}
// ~ Initialize common parameter formessage passing
@@ -457,7 +457,7 @@ int _DkReceiveHandle(PAL_HANDLE hdl, PAL_HANDLE * cargo)
for (int i = 0 ; i < MAX_FDS ; i++)
if (hdl_hdr.fds & (1U << i)) {
if (n < total_fds) {
- HANDLE_HDR(handle)->fds[i] = ((int *) CMSG_DATA(chdr))[n++];
+ handle->generic.fds[i] = ((int *) CMSG_DATA(chdr))[n++];
} else {
HANDLE_HDR(handle)->flags &= ~(RFD(i)|WFD(i));
}
diff --git a/Pal/src/host/Linux/pal.map b/Pal/src/host/Linux/pal.map
index b65df7c8..4c12ab99 100644
--- a/Pal/src/host/Linux/pal.map
+++ b/Pal/src/host/Linux/pal.map
@@ -9,9 +9,9 @@ PAL {
DkThreadCreate; DkThreadDelayExecution;
DkThreadYieldExecution; DkThreadExit; DkThreadResume;
- DkSemaphoreCreate; DkNotificationEventCreate;
+ DkMutexCreate; DkNotificationEventCreate;
DkSynchronizationEventCreate;
- DkSemaphoreRelease;
+ DkMutexRelease;
DkEventSet; DkEventClear;
DkObjectsWaitAny;
diff --git a/Pal/src/host/Linux/pal_host.h b/Pal/src/host/Linux/pal_host.h
index ee40c2f3..ff649c08 100644
--- a/Pal/src/host/Linux/pal_host.h
+++ b/Pal/src/host/Linux/pal_host.h
@@ -30,25 +30,25 @@
# error "cannot be included outside PAL"
#endif
-/* internal Mutex design, the structure has to align at integer boundary
- because it is required by futex call. If DEBUG_MUTEX is defined,
- mutex_handle will record the owner of mutex locking. */
+#include
+
+/* Simpler mutex design: a single variable that tracks whether the
+ * mutex is locked (just waste a 64 bit word for now). State is 1 (locked) or
+ * 0 (unlocked).
+ * Keep a count of how many threads are waiting on the mutex.
+ * If DEBUG_MUTEX is defined,
+ * mutex_handle will record the owner of mutex locking. */
typedef struct mutex_handle {
- union {
- unsigned int u;
- struct {
- unsigned char locked;
- unsigned char contended;
- } b;
- };
+ volatile int64_t locked;
+ struct atomic_int nwaiters;
#ifdef DEBUG_MUTEX
int owner;
#endif
} PAL_LOCK;
/* Initializer of Mutexes */
-#define MUTEX_HANDLE_INIT { .u = 0 }
-#define INIT_MUTEX_HANDLE(m) do { m->u = 0; } while (0)
+#define MUTEX_HANDLE_INIT { .locked = 0, .nwaiters.counter = 0 }
+#define INIT_MUTEX_HANDLE(m) do { m->locked = 0; atomic_set(&m->nwaiters, 0); } while (0)
#define LOCK_INIT MUTEX_HANDLE_INIT
#define INIT_LOCK(lock) INIT_MUTEX_HANDLE(lock);
@@ -56,122 +56,105 @@ typedef struct mutex_handle {
#define _DkInternalLock _DkMutexLock
#define _DkInternalUnlock _DkMutexUnlock
-typedef union pal_handle
+typedef struct pal_handle
{
/* TSAI: Here we define the internal types of PAL_HANDLE
* in PAL design, user has not to access the content inside the
* handle, also there is no need to allocate the internal
* handles, so we hide the type name of these handles on purpose.
*/
+ PAL_HDR hdr;
+
+ union {
+ struct {
+ PAL_IDX fds[2];
+ } generic;
- struct {
- PAL_IDX type;
- PAL_REF ref;
- PAL_FLG flags;
- PAL_IDX fds[];
- } hdr;
+ struct {
+ PAL_IDX fd;
+ PAL_NUM offset;
+ PAL_BOL append;
+ PAL_BOL pass;
+ PAL_STR realpath;
+ } file;
+
+ struct {
+ PAL_IDX fd;
+ PAL_NUM pipeid;
+ PAL_BOL nonblocking;
+ } pipe;
- struct {
- PAL_HDR reserved;
- PAL_IDX fd;
- PAL_NUM offset;
- PAL_BOL append;
- PAL_BOL pass;
- PAL_STR realpath;
- } file;
+ struct {
+ PAL_IDX fds[2];
+ PAL_BOL nonblocking;
+ } pipeprv;
- struct {
- PAL_HDR reserved;
- PAL_IDX fd;
- PAL_NUM pipeid;
- PAL_BOL nonblocking;
- } pipe;
+ struct {
+ PAL_IDX fd_in, fd_out;
+ PAL_IDX dev_type;
+ PAL_BOL destroy;
+ PAL_STR realpath;
+ } dev;
- struct {
- PAL_HDR reserved;
- PAL_IDX fds[2];
- PAL_BOL nonblocking;
- } pipeprv;
+ struct {
+ PAL_IDX fd;
+ PAL_STR realpath;
+ PAL_PTR buf;
+ PAL_PTR ptr;
+ PAL_PTR end;
+ PAL_BOL endofstream;
+ } dir;
- struct {
- PAL_HDR reserved;
- PAL_IDX fd_in, fd_out;
- PAL_IDX dev_type;
- PAL_BOL destroy;
- PAL_STR realpath;
- } dev;
+ struct {
+ PAL_IDX fd;
+ PAL_NUM token;
+ } gipc;
- struct {
- PAL_HDR reserved;
- PAL_IDX fd;
- PAL_STR realpath;
- PAL_PTR buf;
- PAL_PTR ptr;
- PAL_PTR end;
- PAL_BOL endofstream;
- } dir;
+ struct {
+ PAL_IDX fd;
+ PAL_PTR bind;
+ PAL_PTR conn;
+ PAL_BOL nonblocking;
+ PAL_BOL reuseaddr;
+ PAL_NUM linger;
+ PAL_NUM receivebuf;
+ PAL_NUM sendbuf;
+ PAL_NUM receivetimeout;
+ PAL_NUM sendtimeout;
+ PAL_BOL tcp_cork;
+ PAL_BOL tcp_keepalive;
+ PAL_BOL tcp_nodelay;
+ } sock;
- struct {
- PAL_HDR reserved;
- PAL_IDX fd;
- PAL_NUM token;
- } gipc;
+ struct {
+ PAL_IDX stream_in, stream_out;
+ PAL_IDX cargo;
+ PAL_IDX pid;
+ PAL_BOL nonblocking;
+ } process;
- struct {
- PAL_HDR reserved;
- PAL_IDX fd;
- PAL_PTR bind;
- PAL_PTR conn;
- PAL_BOL nonblocking;
- PAL_BOL reuseaddr;
- PAL_NUM linger;
- PAL_NUM receivebuf;
- PAL_NUM sendbuf;
- PAL_NUM receivetimeout;
- PAL_NUM sendtimeout;
- PAL_BOL tcp_cork;
- PAL_BOL tcp_keepalive;
- PAL_BOL tcp_nodelay;
- } sock;
+ struct {
+ PAL_IDX cli;
+ PAL_IDX srv;
+ PAL_IDX port;
+ PAL_BOL nonblocking;
+ PAL_PTR addr;
+ } mcast;
- struct {
- PAL_HDR reserved;
- PAL_IDX stream_in, stream_out;
- PAL_IDX cargo;
- PAL_IDX pid;
- PAL_BOL nonblocking;
- } process;
+ struct {
+ PAL_IDX tid;
+ } thread;
- struct {
- PAL_HDR reserved;
- PAL_IDX cli;
- PAL_IDX srv;
- PAL_IDX port;
- PAL_BOL nonblocking;
- PAL_PTR addr;
- } mcast;
-
- struct {
- PAL_HDR reserved;
- PAL_IDX tid;
- } thread;
-
- struct {
- PAL_HDR reserved;
- struct atomic_int nwaiters;
- PAL_NUM max_value;
- union {
+ struct {
struct mutex_handle mut;
- struct atomic_int i;
- } value;
- } semaphore;
+ } mutex;
- struct {
- PAL_HDR reserved;
- struct atomic_int signaled;
- struct atomic_int nwaiters;
- PAL_BOL isnotification;
- } event;
+ struct {
+ struct atomic_int signaled;
+ struct atomic_int nwaiters;
+ PAL_BOL isnotification;
+ } event;
+ };
} * PAL_HANDLE;
#define RFD(n) (00001 << (n))
diff --git a/Pal/src/host/Skeleton/pal_host.h b/Pal/src/host/Skeleton/pal_host.h
index fa9910af..3ecc89cd 100644
--- a/Pal/src/host/Skeleton/pal_host.h
+++ b/Pal/src/host/Skeleton/pal_host.h
@@ -33,69 +33,73 @@
typedef int PAL_LOCK;
#define LOCK_INIT (0)
-typedef union pal_handle
+typedef struct pal_handle
{
/* TSAI: Here we define the internal types of PAL_HANDLE
* in PAL design, user has not to access the content inside the
* handle, also there is no need to allocate the internal
* handles, so we hide the type name of these handles on purpose.
*/
+ PAL_HDR hdr;
+
+ union {
+ struct {
+ PAL_IDX fds[2];
+ } generic;
- struct {
- PAL_IDX type;
- PAL_REF ref;
- PAL_FLG flags;
- PAL_IDX fds[];
- } hdr;
-
- struct {
- PAL_HDR reserved;
- } file;
-
- struct {
- PAL_HDR reserved;
- } pipe;
-
- struct {
- PAL_HDR reserved;
- } pipeprv;
-
- struct {
- PAL_HDR reserved;
- PAL_IDX dev_type;
- } dev;
-
- struct {
- PAL_HDR reserved;
- } dir;
-
- struct {
- PAL_HDR reserved;
- } gipc;
-
- struct {
- PAL_HDR reserved;
- } sock;
-
- struct {
- PAL_HDR reserved;
- } process;
-
- struct {
- PAL_HDR reserved;
- } mcast;
-
- struct {
- PAL_HDR reserved;
- } thread;
-
- struct {
- PAL_HDR reserved;
- } semaphore;
-
- struct {
- PAL_HDR reserved;
- } event;
+ /* DP: Here we just define a placeholder fd; place your details here.
+ * Not every type requires an fd either - this is up to your
+ * host-specific code.
+ */
+ struct {
+ PAL_IDX fd;
+ } file;
+
+ struct {
+ PAL_IDX fd;
+ } pipe;
+
+ struct {
+ PAL_IDX fd;
+ } pipeprv;
+
+ struct {
+ PAL_IDX fd;
+ PAL_IDX dev_type;
+ } dev;
+
+ struct {
+ PAL_IDX fd;
+ } dir;
+
+ struct {
+ PAL_IDX fd;
+ } gipc;
+
+ struct {
+ PAL_IDX fd;
+ } sock;
+
+ struct {
+ PAL_IDX fd;
+ } process;
+
+ struct {
+ PAL_IDX fd;
+ } mcast;
+
+ struct {
+ PAL_IDX fd;
+ } thread;
+
+ struct {
+ PAL_IDX fd;
+ } semaphore;
+
+ struct {
+ PAL_IDX fd;
+ } event;
+ };
} * PAL_HANDLE;
#endif /* PAL_HOST_H */
diff --git a/Pal/src/pal.h b/Pal/src/pal.h
index 3bedf088..9bdc9d0a 100644
--- a/Pal/src/pal.h
+++ b/Pal/src/pal.h
@@ -33,19 +33,12 @@
typedef unsigned long PAL_NUM;
typedef const char * PAL_STR;
typedef void * PAL_PTR;
-typedef unsigned int PAL_FLG;
-typedef unsigned int PAL_IDX;
+typedef uint32_t PAL_FLG;
+typedef uint32_t PAL_IDX;
typedef bool PAL_BOL;
#ifdef IN_PAL
-struct atomic_int {
- volatile int counter;
-}
-#ifdef __GNUC__
-__attribute__((aligned(sizeof(int))))
-#endif
-;
-
+#include
typedef struct atomic_int PAL_REF;
typedef struct {
@@ -60,12 +53,14 @@ typedef struct {
# define HANDLE_HDR(handle) (&((handle)->hdr))
# endif
-# define SET_HANDLE_TYPE(handle, t) \
- do { \
- HANDLE_HDR(handle)->type = pal_type_##t;\
- HANDLE_HDR(handle)->ref.counter = 0; \
- HANDLE_HDR(handle)->flags = 0; \
- } while (0)
+static inline void init_handle_hdr(PAL_HDR *hdr, int pal_type) {
+ hdr->type = pal_type;
+ hdr->ref.counter = 1;
+ hdr->flags = 0;
+}
+
+# define SET_HANDLE_TYPE(handle, t) \
+ init_handle_hdr(HANDLE_HDR(handle), pal_type_##t)
# define IS_HANDLE_TYPE(handle, t) \
(HANDLE_HDR(handle)->type == pal_type_##t)
@@ -115,7 +110,7 @@ enum {
pal_type_process,
pal_type_mcast,
pal_type_thread,
- pal_type_semaphore,
+ pal_type_mutex,
pal_type_event,
pal_type_gipc,
PAL_HANDLE_TYPE_BOUND,
@@ -428,26 +423,16 @@ void DkExceptionReturn (PAL_PTR event);
* We may want to replace it with a PAL_HANDLE. Ideally, either use PAL_HANDLE
* or threadHandle.
*/
-/* maxcount sets the number of threads allowed to hold the semaphore
- * at once. For 1, this becomes a mutex.
- * initialCount of 0 is totally unlocked; an initialCount that
- * equals maxCount means that all resources are taken. */
+/* Create a Mutex.
+ * initialCount of 0 is totally unlocked; an initialCount of 1
+ * is initialized to locked. */
PAL_HANDLE
-DkSemaphoreCreate (PAL_NUM initialCount, PAL_NUM maxCount);
+DkMutexCreate (PAL_NUM initialCount);
-/* DkSemaphoreDestroy deprecated, replaced by DkObjectClose */
-
-/* TSAI: I preserve this API because DkObjectsWaitAny can't acquire multiple
- * counts of a semaphore. Acquiring multiple counts is required for
- * implementing a read-write-lock. To make this API complementary to
- * DkObjectsWaitAny, I added a 'timeout' to its arguments */
-
-/* DkSemaphoreAcquire deprecated */
+/* Destroy a mutex using DkObjectClose */
void
-DkSemaphoreRelease (PAL_HANDLE semaphoreHandle, PAL_NUM count);
-
-/* DkSemaphoreGetCurrentCount deprecated */
+DkMutexRelease (PAL_HANDLE mutexHandle);
PAL_HANDLE
DkNotificationEventCreate (PAL_BOL initialState);
diff --git a/Pal/src/pal_internal.h b/Pal/src/pal_internal.h
index 029378f1..ec43102a 100644
--- a/Pal/src/pal_internal.h
+++ b/Pal/src/pal_internal.h
@@ -155,38 +155,14 @@ static inline unsigned int hash64 (unsigned long key)
/* We allow dynamic size handle allocation. Here is some macro to help
deciding the actual size of the handle */
extern PAL_HANDLE _h;
-#define HANDLE_SIZE(type) (sizeof(_h->type))
+#define HANDLE_SIZE(type) (sizeof(*_h))
#define UNKNOWN_HANDLE(handle) \
(PAL_GET_TYPE(handle) == 0 || PAL_GET_TYPE(handle) >= PAL_HANDLE_TYPE_BOUND)
static inline int handle_size (PAL_HANDLE handle)
{
- static int handle_sizes[PAL_HANDLE_TYPE_BOUND]
- = { 0,
- [pal_type_file] = sizeof(handle->file),
- [pal_type_pipe] = sizeof(handle->pipe),
- [pal_type_pipesrv] = sizeof(handle->pipe),
- [pal_type_pipecli] = sizeof(handle->pipe),
- [pal_type_pipeprv] = sizeof(handle->pipeprv),
- [pal_type_dev] = sizeof(handle->dev),
- [pal_type_dir] = sizeof(handle->dir),
- [pal_type_tcp] = sizeof(handle->sock),
- [pal_type_tcpsrv] = sizeof(handle->sock),
- [pal_type_udp] = sizeof(handle->sock),
- [pal_type_udpsrv] = sizeof(handle->sock),
- [pal_type_process] = sizeof(handle->process),
- [pal_type_mcast] = sizeof(handle->mcast),
- [pal_type_thread] = sizeof(handle->thread),
- [pal_type_semaphore] = sizeof(handle->semaphore),
- [pal_type_event] = sizeof(handle->event),
- [pal_type_gipc] = sizeof(handle->gipc),
- };
-
- if (UNKNOWN_HANDLE(handle))
- return 0;
- else
- return handle_sizes[PAL_GET_TYPE(handle)];
+ return sizeof(*handle);
}
#ifndef ENTER_PAL_CALL
@@ -324,13 +300,13 @@ int _DkProcessCreate (PAL_HANDLE * handle, const char * uri,
void _DkProcessExit (int exitCode);
int _DkProcessSandboxCreate (const char * manifest, int flags);
-/* DkSemaphore calls */
-int _DkSemaphoreCreate (PAL_HANDLE handle, int initialCount, int maxCount);
-void _DkSemaphoreDestroy (PAL_HANDLE semaphoreHandle);
-int _DkSemaphoreAcquire (PAL_HANDLE sem, int count);
-int _DkSemaphoreAcquireTimeout (PAL_HANDLE sem, int count, uint64_t timeout);
-void _DkSemaphoreRelease (PAL_HANDLE sem, int count);
-int _DkSemaphoreGetCurrentCount (PAL_HANDLE sem);
+/* DkMutex calls */
+int _DkMutexCreate (PAL_HANDLE handle, int initialCount);
+void _DkMutexDestroy (PAL_HANDLE semaphoreHandle);
+int _DkMutexAcquire (PAL_HANDLE sem);
+int _DkMutexAcquireTimeout (PAL_HANDLE sem, int timeout);
+void _DkMutexRelease (PAL_HANDLE sem);
+int _DkMutexGetCurrentCount (PAL_HANDLE sem);
/* DkEvent calls */
int _DkEventCreate (PAL_HANDLE * event, bool initialState,