diff --git a/BasiliskII/src/Unix/CMakeLists.txt b/BasiliskII/src/Unix/CMakeLists.txt index 4454d69a..c47046b3 100644 --- a/BasiliskII/src/Unix/CMakeLists.txt +++ b/BasiliskII/src/Unix/CMakeLists.txt @@ -48,7 +48,6 @@ set(BasiliskII_SRCS ../extfs.cpp ../user_strings.cpp user_strings_unix.cpp - rpc_unix.cpp # XPLAT_SRCS ../CrossPlatform/vm_alloc.cpp ../CrossPlatform/sigsegv.cpp @@ -67,7 +66,6 @@ set(BasiliskII_SRCS ../dummy/scsi_dummy.cpp #audio src ../SDL/audio_sdl.cpp - #sem src: posix_sem.cpp #ui src ../dummy/prefs_editor_dummy.cpp #extra sys diff --git a/BasiliskII/src/Unix/main_unix.cpp b/BasiliskII/src/Unix/main_unix.cpp index 05f9717d..36814ffa 100644 --- a/BasiliskII/src/Unix/main_unix.cpp +++ b/BasiliskII/src/Unix/main_unix.cpp @@ -55,7 +55,6 @@ using std::string; #include "main.h" #include "vm_alloc.h" #include "sigsegv.h" -#include "rpc.h" #if USE_JIT extern void flush_icache_range(uint8 *start, uint32 size); // from compemu_support.cpp @@ -108,11 +107,6 @@ static timer_t timer; // 60Hz timer #endif #endif // !HAVE_PTHREADS - -static rpc_connection_t *gui_connection = NULL; // RPC connection to the GUI -static const char *gui_connection_path = NULL; // GUI connection identifier - - // Prototypes static int xpram_func(void *arg); static int tick_func(void *arg); @@ -300,12 +294,6 @@ int main(int argc, char **argv) for (int i=1; i -#include -#include -#include -#include - -#include "semaphore.h" - -extern "C" { - -int sem_init(sem_t* sem, int pshared, unsigned int value) -{ - if(sem==NULL||value>SEM_VALUE_MAX) { - errno = EINVAL; - return -1; - } - if(pshared) { - errno = ENOSYS; - return -1; - } - pthread_mutex_init(&sem->sem_lock, NULL); - sem->sem_value = value; - sem->sem_waiting = 0; - return 0; -} - - -int sem_destroy(sem_t* sem) -{ - if(sem==NULL) { - errno = EINVAL; - return -1; - } - if(sem->sem_waiting) { - errno = EBUSY; - return -1; - } - pthread_mutex_destroy(&sem->sem_lock); - sem->sem_waiting = 0; - sem->sem_value = 0; - return 0; -} - -sem_t sem_open(const char* name, int oflag, ...) -{ - errno = ENOSYS; - return *(sem_t*)NULL; -} - -int sem_close(sem_t* sem) -{ - errno = ENOSYS; - return -1; -} - -int sem_unlink(const char* name) -{ - errno = ENOSYS; - return -1; -} - -int sem_wait(sem_t* sem) -{ - struct timespec req = { 1, 0 }; - - if(sem==NULL) { - errno = EINVAL; - return -1; - } - pthread_mutex_lock(&sem->sem_lock); - sem->sem_waiting++; - if(sem->sem_value > 0) { - --sem->sem_value; - return 0; - } - while(!sem->sem_value) nanosleep(NULL, &req); - pthread_mutex_unlock(&sem->sem_lock); - return 0; -} - -int sem_trywait(sem_t* sem) -{ - errno = ENOSYS; - return -1; -} - -int sem_post(sem_t* sem) -{ - if(sem==NULL) { - errno = EINVAL; - return -1; - } - if(!sem->sem_waiting) { - if(sem->sem_value >= SEM_VALUE_MAX) { - errno = ERANGE; - pthread_mutex_unlock(&sem->sem_lock); - return -1; - } - ++sem->sem_value; - pthread_mutex_unlock(&sem->sem_lock); - } - else { - sem->sem_waiting--; - ++sem->sem_value; -// pthread_mutex_unlock(&sem->sem_lock); - } - return 0; -} - -int sem_getvalue(sem_t* sem, int* sval) -{ - errno = ENOSYS; - return -1; -} - -} diff --git a/BasiliskII/src/Unix/rpc.h b/BasiliskII/src/Unix/rpc.h deleted file mode 100644 index a43dfaef..00000000 --- a/BasiliskII/src/Unix/rpc.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * rpc.h - Remote Procedure Calls - * - * Basilisk II (C) 1997-2008 Christian Bauer - * Contributed by Gwenole Beauchesne - * - * This program 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 2 of the License, or - * (at your option) any later version. - * - * This program 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef RPC_H -#define RPC_H - -// Error Types -enum { - RPC_ERROR_NO_ERROR = 0, - RPC_ERROR_GENERIC = -1000, - RPC_ERROR_ERRNO_SET = -1001, - RPC_ERROR_NO_MEMORY = -1002, - RPC_ERROR_CONNECTION_NULL = -1003, - RPC_ERROR_CONNECTION_TYPE_MISMATCH = -1004, - RPC_ERROR_MESSAGE_TRUNCATED = -1005, - RPC_ERROR_MESSAGE_ARGUMENT_MISMATCH = -1006, - RPC_ERROR_MESSAGE_ARGUMENT_UNKNOWN = -1007, -}; - -// Connection Handling -typedef struct rpc_connection_t rpc_connection_t; -extern rpc_connection_t *rpc_init_server(const char *ident); -extern rpc_connection_t *rpc_init_client(const char *ident); -extern int rpc_exit(rpc_connection_t *connection); -extern int rpc_listen_socket(rpc_connection_t *connection); -extern int rpc_listen(rpc_connection_t *connection); -extern int rpc_dispatch(rpc_connection_t *connection); -extern int rpc_wait_dispatch(rpc_connection_t *connection, int timeout); -extern int rpc_connection_busy(rpc_connection_t *connection); - -// Message Passing -enum { - RPC_TYPE_INVALID = 0, - RPC_TYPE_CHAR = -2000, - RPC_TYPE_BOOLEAN = -2001, - RPC_TYPE_INT32 = -2002, - RPC_TYPE_UINT32 = -2003, - RPC_TYPE_STRING = -2004, - RPC_TYPE_ARRAY = -2005, -}; -typedef struct rpc_message_t rpc_message_t; -extern int rpc_message_send_char(rpc_message_t *message, char c); -extern int rpc_message_send_int32(rpc_message_t *message, int32_t value); -extern int rpc_message_send_uint32(rpc_message_t *message, uint32_t value); -extern int rpc_message_send_string(rpc_message_t *message, const char *str); -extern int rpc_message_send_bytes(rpc_message_t *message, unsigned char *bytes, int count); -extern int rpc_message_recv_char(rpc_message_t *message, char *ret); -extern int rpc_message_recv_int32(rpc_message_t *message, int32_t *ret); -extern int rpc_message_recv_uint32(rpc_message_t *message, uint32_t *ret); -extern int rpc_message_recv_string(rpc_message_t *message, char **ret); -extern int rpc_message_recv_bytes(rpc_message_t *message, unsigned char *bytes, int count); -typedef int (*rpc_message_callback_t)(rpc_message_t *message, void *p_value); -typedef struct { - int id; - int size; - rpc_message_callback_t send_callback; - rpc_message_callback_t recv_callback; -} rpc_message_descriptor_t; -extern int rpc_message_add_callbacks(const rpc_message_descriptor_t *descs, int n_descs); - -// Method Callbacks Handling -typedef int (*rpc_method_callback_t)(rpc_connection_t *connection); -typedef struct { - int id; - rpc_method_callback_t callback; -} rpc_method_descriptor_t; -extern int rpc_method_add_callbacks(rpc_connection_t *connection, const rpc_method_descriptor_t *descs, int n_descs); -extern int rpc_method_remove_callback_id(rpc_connection_t *connection, int id); -extern int rpc_method_remove_callbacks(rpc_connection_t *connection, const rpc_method_descriptor_t *descs, int n_descs); - -// Remote Procedure Call (method invocation) -extern int rpc_method_invoke(rpc_connection_t *connection, int method, ...); -extern int rpc_method_wait_for_reply(rpc_connection_t *connection, ...); -extern int rpc_method_get_args(rpc_connection_t *connection, ...); -extern int rpc_method_send_reply(rpc_connection_t *connection, ...); - -// Message Protocol -enum { - RPC_METHOD_ERROR_ALERT = 1, - RPC_METHOD_WARNING_ALERT, - RPC_METHOD_EXIT -}; - -#endif /* RPC_H */ diff --git a/BasiliskII/src/Unix/rpc_unix.cpp b/BasiliskII/src/Unix/rpc_unix.cpp deleted file mode 100644 index cbc23b60..00000000 --- a/BasiliskII/src/Unix/rpc_unix.cpp +++ /dev/null @@ -1,1257 +0,0 @@ -/* - * rpc_unix.cpp - Remote Procedure Calls, Unix specific backend - * - * Basilisk II (C) 1997-2008 Christian Bauer - * Contributed by Gwenole Beauchesne - * - * This program 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 2 of the License, or - * (at your option) any later version. - * - * This program 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * NOTES: - * - this is subject to rewrite but the API is to be kept intact - * - this RPC system is very minimal and only suited for 1:1 communication - * - * TODO: - * - better failure conditions - * - windows rpc - */ - -#include "sysdeps.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rpc.h" - -#define DEBUG 0 -#include "debug.h" - -#define NON_BLOCKING_IO 0 - -/* ====================================================================== */ -/* === PThreads Glue === */ -/* ====================================================================== */ - -//#define USE_THREADS - -#ifndef USE_THREADS -#define pthread_t void * -#define pthread_cancel(th) -#define pthread_join(th, ret) -#define pthread_testcancel() -#define pthread_create(th, attr, start, arg) dummy_thread_create() -static inline int dummy_thread_create(void) { errno = ENOSYS; return -1; } - -#undef pthread_mutex_t -#define pthread_mutex_t volatile int -#undef pthread_mutex_lock -#define pthread_mutex_lock(m) -1 -#undef pthread_mutex_unlock -#define pthread_mutex_unlock(m) -1 -#undef PTHREAD_MUTEX_INITIALIZER -#define PTHREAD_MUTEX_INITIALIZER 0 -#endif - - -/* ====================================================================== */ -/* === RPC Connection Handling === */ -/* ====================================================================== */ - -// Connection type -enum { - RPC_CONNECTION_SERVER, - RPC_CONNECTION_CLIENT, -}; - -// Connection status -enum { - RPC_STATUS_IDLE, - RPC_STATUS_BUSY, -}; - -// Client / Server connection -struct rpc_connection_t { - int type; - int status; - int socket; - char *socket_path; - int server_socket; - int server_thread_active; - pthread_t server_thread; - rpc_method_descriptor_t *callbacks; - int n_callbacks; - int send_offset; - char send_buffer[BUFSIZ]; -}; - -#define return_error(ERROR) do { error = (ERROR); goto do_return; } while (0) - -// Set connection status (XXX protect connection with a lock?) -static inline void rpc_connection_set_status(rpc_connection_t *connection, int status) -{ - connection->status = status; -} - -// Returns TRUE if the connection is busy (e.g. waiting for a reply) -int rpc_connection_busy(rpc_connection_t *connection) -{ - return connection && connection->status == RPC_STATUS_BUSY; -} - -// Prepare socket path for addr.sun_path[] -static int _rpc_socket_path(char **pathp, const char *ident) -{ - int i, len; - len = strlen(ident); - - if (pathp == NULL) - return 0; - - char *path; -#if USE_ABSTRACT_NAMESPACES - const int len_bias = 1; - if ((path = (char *)malloc(len + len_bias + 1)) == NULL) - return 0; - path[0] = 0; - strcpy(&path[len_bias], ident); -#else - const int len_bias = 5; - if ((path = (char *)malloc(len + len_bias + 1)) == NULL) - return 0; - strcpy(path, "/tmp/"); - for (i = 0; i < len; i++) { - char ch = ident[i]; - if (ch == '/') - ch = '_'; - path[len_bias + i] = ch; - } -#endif - len += len_bias; - path[len] = '\0'; - if (*pathp) - free(*pathp); - *pathp = path; - return len; -} - -// Initialize server-side RPC system -rpc_connection_t *rpc_init_server(const char *ident) -{ - D(bug("rpc_init_server ident='%s'\n", ident)); - - rpc_connection_t *connection; - struct sockaddr_un addr; - socklen_t addr_len; - - if (ident == NULL) - return NULL; - - connection = (rpc_connection_t *)malloc(sizeof(*connection)); - if (connection == NULL) - return NULL; - connection->type = RPC_CONNECTION_SERVER; - connection->status = RPC_STATUS_IDLE; - connection->socket = -1; - connection->server_thread_active = 0; - connection->callbacks = NULL; - connection->n_callbacks = 0; - - if ((connection->server_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - perror("server socket"); - free(connection); - return NULL; - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - connection->socket_path = NULL; - addr_len = _rpc_socket_path(&connection->socket_path, ident); - memcpy(&addr.sun_path[0], connection->socket_path, addr_len); - addr_len += sizeof(struct sockaddr_un) - sizeof(addr.sun_path); - - if (bind(connection->server_socket, (struct sockaddr *)&addr, addr_len) < 0) { - perror("server bind"); - close(connection->socket); - free(connection); - return NULL; - } - - if (listen(connection->server_socket, 1) < 0) { - perror("server listen"); - close(connection->socket); - free(connection); - return NULL; - } - - return connection; -} - -// Initialize client-side RPC system -rpc_connection_t *rpc_init_client(const char *ident) -{ - D(bug("rpc_init_client ident='%s'\n", ident)); - - rpc_connection_t *connection; - struct sockaddr_un addr; - socklen_t addr_len; - - if (ident == NULL) - return NULL; - - connection = (rpc_connection_t *)malloc(sizeof(*connection)); - if (connection == NULL) - return NULL; - connection->type = RPC_CONNECTION_CLIENT; - connection->status = RPC_STATUS_IDLE; - connection->server_socket = -1; - connection->callbacks = NULL; - connection->n_callbacks = 0; - - if ((connection->socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - perror("client socket"); - free(connection); - return NULL; - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - connection->socket_path = NULL; - addr_len = _rpc_socket_path(&connection->socket_path, ident); - memcpy(&addr.sun_path[0], connection->socket_path, addr_len); - addr_len += sizeof(struct sockaddr_un) - sizeof(addr.sun_path); - - // Wait at most 5 seconds for server to initialize - const int N_CONNECT_WAIT_DELAY = 10; - int n_connect_attempts = 5000 / N_CONNECT_WAIT_DELAY; - if (n_connect_attempts == 0) - n_connect_attempts = 1; - while (n_connect_attempts > 0) { - if (connect(connection->socket, (struct sockaddr *)&addr, addr_len) == 0) - break; - if (n_connect_attempts > 1 && errno != ECONNREFUSED && errno != ENOENT) { - perror("client_connect"); - close(connection->socket); - free(connection); - return NULL; - } - n_connect_attempts--; - usleep(N_CONNECT_WAIT_DELAY); - } - if (n_connect_attempts == 0) { - close(connection->socket); - free(connection); - return NULL; - } - - return connection; -} - -// Close RPC connection -int rpc_exit(rpc_connection_t *connection) -{ - D(bug("rpc_exit\n")); - - if (connection == NULL) - return RPC_ERROR_CONNECTION_NULL; - - if (connection->socket_path) { - if (connection->socket_path[0]) - unlink(connection->socket_path); - free(connection->socket_path); - } - - if (connection->type == RPC_CONNECTION_SERVER) { - if (connection->server_thread_active) { - pthread_cancel(connection->server_thread); - pthread_join(connection->server_thread, NULL); - } - if (connection->socket != -1) - close(connection->socket); - if (connection->server_socket != -1) - close(connection->server_socket); - } - else { - if (connection->socket != -1) - close(connection->socket); - } - - if (connection->callbacks) - free(connection->callbacks); - free(connection); - - return RPC_ERROR_NO_ERROR; -} - -// Wait for a message to arrive on the connection port -static inline int _rpc_wait_dispatch(rpc_connection_t *connection, int timeout) -{ - struct timeval tv; - tv.tv_sec = timeout / 1000000; - tv.tv_usec = timeout % 1000000; - - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(connection->socket, &rfds); - return select(connection->socket + 1, &rfds, NULL, NULL, &tv); -} - -int rpc_wait_dispatch(rpc_connection_t *connection, int timeout) -{ - if (connection == NULL) - return RPC_ERROR_CONNECTION_NULL; - if (connection->type != RPC_CONNECTION_SERVER) - return RPC_ERROR_CONNECTION_TYPE_MISMATCH; - - return _rpc_wait_dispatch(connection, timeout); -} - -#ifdef USE_THREADS -// Process incoming messages in the background -static void *rpc_server_func(void *arg) -{ - rpc_connection_t *connection = (rpc_connection_t *)arg; - - int ret = rpc_listen_socket(connection); - if (ret < 0) - return NULL; - - connection->server_thread_active = 1; - for (;;) { - // XXX broken MacOS X doesn't implement cancellation points correctly - pthread_testcancel(); - - // wait for data to arrive - int ret = _rpc_wait_dispatch(connection, 50000); - if (ret == 0) - continue; - if (ret < 0) - break; - - rpc_dispatch(connection); - } - connection->server_thread_active = 0; - return NULL; -} -#endif - -// Return listen socket of RPC connection -int rpc_listen_socket(rpc_connection_t *connection) -{ - D(bug("rpc_listen_socket\n")); - - if (connection == NULL) - return RPC_ERROR_CONNECTION_NULL; - if (connection->type != RPC_CONNECTION_SERVER) - return RPC_ERROR_CONNECTION_TYPE_MISMATCH; - - struct sockaddr_un addr; - socklen_t addr_len = sizeof(addr); - if ((connection->socket = accept(connection->server_socket, (struct sockaddr *)&addr, &addr_len)) < 0) { - perror("server accept"); - return RPC_ERROR_ERRNO_SET; - } - -#if NON_BLOCKING_IO - int val = fcntl(connection->socket, F_GETFL, 0); - if (val < 0) { - perror("server fcntl F_GETFL"); - return RPC_ERROR_ERRNO_SET; - } - if (fcntl(connection->socket, F_SETFL, val | O_NONBLOCK) < 0) { - perror("server fcntl F_SETFL"); - return RPC_ERROR_ERRNO_SET; - } -#endif - - return connection->socket; -} - -// Listen for incoming messages on RPC connection -#ifdef USE_THREADS -int rpc_listen(rpc_connection_t *connection) -{ - D(bug("rpc_listen\n")); - - if (pthread_create(&connection->server_thread, NULL, rpc_server_func, connection) != 0) { - perror("server thread"); - return RPC_ERROR_ERRNO_SET; - } - - return RPC_ERROR_NO_ERROR; -} -#endif - - -/* ====================================================================== */ -/* === Message Passing === */ -/* ====================================================================== */ - -// Message markers -enum { - RPC_MESSAGE_START = -3000, - RPC_MESSAGE_END = -3001, - RPC_MESSAGE_ACK = -3002, - RPC_MESSAGE_REPLY = -3003, - RPC_MESSAGE_FAILURE = -3004, -}; - -// Message type -struct rpc_message_t { - int socket; - int offset; - unsigned char buffer[BUFSIZ]; -}; - -// User-defined marshalers -static struct { - rpc_message_descriptor_t *descs; - int last; - int count; -} g_message_descriptors = { NULL, 0, 0 }; -static pthread_mutex_t g_message_descriptors_lock = PTHREAD_MUTEX_INITIALIZER; - -// Add a user-defined marshaler -static int rpc_message_add_callback(const rpc_message_descriptor_t *desc) -{ - D(bug("rpc_message_add_callback\n")); - - const int N_ENTRIES_ALLOC = 8; - int error = RPC_ERROR_NO_ERROR; - - pthread_mutex_lock(&g_message_descriptors_lock); - if (g_message_descriptors.descs == NULL) { - g_message_descriptors.count = N_ENTRIES_ALLOC; - if ((g_message_descriptors.descs = (rpc_message_descriptor_t *)malloc(g_message_descriptors.count * sizeof(g_message_descriptors.descs[0]))) == NULL) { - pthread_mutex_unlock(&g_message_descriptors_lock); - return RPC_ERROR_NO_MEMORY; - } - g_message_descriptors.last = 0; - } - else if (g_message_descriptors.last >= g_message_descriptors.count) { - g_message_descriptors.count += N_ENTRIES_ALLOC; - if ((g_message_descriptors.descs = (rpc_message_descriptor_t *)realloc(g_message_descriptors.descs, g_message_descriptors.count * sizeof(g_message_descriptors.descs[0]))) == NULL) { - pthread_mutex_unlock(&g_message_descriptors_lock); - return RPC_ERROR_NO_MEMORY; - } - } - - // XXX only one callback per ID - int i; - for (i = 0; i < g_message_descriptors.last; i++) { - if (g_message_descriptors.descs[i].id == desc->id) { - pthread_mutex_unlock(&g_message_descriptors_lock); - return RPC_ERROR_NO_ERROR; - } - } - - g_message_descriptors.descs[g_message_descriptors.last++] = *desc; - pthread_mutex_unlock(&g_message_descriptors_lock); - return error; -} - -// Add user-defined marshalers -int rpc_message_add_callbacks(const rpc_message_descriptor_t *descs, int n_descs) -{ - D(bug("rpc_message_add_callbacks\n")); - - int i, error; - for (i = 0; i < n_descs; i++) { - if ((error = rpc_message_add_callback(&descs[i])) < 0) - return error; - } - - return RPC_ERROR_NO_ERROR; -} - -// Find user-defined marshaler -static rpc_message_descriptor_t *rpc_message_find_descriptor(int id) -{ - D(bug("rpc_message_find_descriptor\n")); - - if (g_message_descriptors.descs) { - int i; - for (i = 0; i < g_message_descriptors.count; i++) { - if (g_message_descriptors.descs[i].id == id) - return &g_message_descriptors.descs[i]; - } - } - - return NULL; -} - -// Initialize message -static inline void rpc_message_init(rpc_message_t *message, rpc_connection_t *connection) -{ - message->socket = connection->socket; - message->offset = 0; -} - -// Send BYTES -static inline int _rpc_message_send_bytes(rpc_message_t *message, unsigned char *bytes, int count) -{ - if (send(message->socket, bytes, count, 0) != count) - return RPC_ERROR_ERRNO_SET; - return RPC_ERROR_NO_ERROR; -} - -// Send message on wire -static inline int rpc_message_flush(rpc_message_t *message) -{ - int error = _rpc_message_send_bytes(message, message->buffer, message->offset); - message->offset = 0; - return error; -} - -// Send BYTES (public interface, may need to flush internal buffer) -int rpc_message_send_bytes(rpc_message_t *message, unsigned char *bytes, int count) -{ - if (message->offset > 0) { - int error = rpc_message_flush(message); - if (error != RPC_ERROR_NO_ERROR) - return error; - } - return _rpc_message_send_bytes(message, bytes, count); -} - -// Send BYTES (buffered) -static inline void _rpc_message_send_bytes_buffered(rpc_message_t *message, unsigned char *bytes, int count) -{ - memcpy(&message->buffer[message->offset], bytes, count); - message->offset += count; -} - -// Send CHAR -int rpc_message_send_char(rpc_message_t *message, char c) -{ - D(bug(" send CHAR '%c'\n", c)); - - unsigned char e_value = c; - if (message->offset + sizeof(e_value) >= sizeof(message->buffer)) { - int error = rpc_message_flush(message); - if (error != RPC_ERROR_NO_ERROR) - return error; - } - _rpc_message_send_bytes_buffered(message, (unsigned char *)&e_value, sizeof(e_value)); - return RPC_ERROR_NO_ERROR; -} - -// Send INT32 -int rpc_message_send_int32(rpc_message_t *message, int32_t value) -{ - D(bug(" send INT32 %d\n", value)); - - int32_t e_value = htonl(value); - if (message->offset + sizeof(e_value) >= sizeof(message->buffer)) { - int error = rpc_message_flush(message); - if (error != RPC_ERROR_NO_ERROR) - return error; - } - _rpc_message_send_bytes_buffered(message, (unsigned char *)&e_value, sizeof(e_value)); - return RPC_ERROR_NO_ERROR; -} - -// Send UINT32 -int rpc_message_send_uint32(rpc_message_t *message, uint32_t value) -{ - D(bug(" send UINT32 %u\n", value)); - - uint32_t e_value = htonl(value); - if (message->offset + sizeof(e_value) >= sizeof(message->buffer)) { - int error = rpc_message_flush(message); - if (error != RPC_ERROR_NO_ERROR) - return error; - } - _rpc_message_send_bytes_buffered(message, (unsigned char *)&e_value, sizeof(e_value)); - return RPC_ERROR_NO_ERROR; -} - -// Send STRING -int rpc_message_send_string(rpc_message_t *message, const char *str) -{ - D(bug(" send STRING \"%s\"\n", str)); - - int error, length = str ? strlen(str) : 0; - uint32_t e_value = htonl(length); - if (message->offset + sizeof(e_value) >= sizeof(message->buffer)) { - error = rpc_message_flush(message); - if (error != RPC_ERROR_NO_ERROR) - return error; - } - _rpc_message_send_bytes_buffered(message, (unsigned char *)&e_value, sizeof(e_value)); - error = rpc_message_flush(message); - if (error != RPC_ERROR_NO_ERROR) - return error; - D(bug("str=%p\n", str)); - return _rpc_message_send_bytes(message, (unsigned char *)str, length); -} - -// Send message arguments -static int rpc_message_send_args(rpc_message_t *message, va_list args) -{ - int type; - rpc_message_descriptor_t *desc; - while ((type = va_arg(args, int)) != RPC_TYPE_INVALID) { - int error = rpc_message_send_int32(message, type); - if (error != RPC_ERROR_NO_ERROR) - return error; - switch (type) { - case RPC_TYPE_CHAR: - error = rpc_message_send_char(message, (char )va_arg(args, int)); - break; - case RPC_TYPE_BOOLEAN: - case RPC_TYPE_INT32: - error = rpc_message_send_int32(message, va_arg(args, int)); - break; - case RPC_TYPE_UINT32: - error = rpc_message_send_uint32(message, va_arg(args, unsigned int)); - break; - case RPC_TYPE_STRING: - error = rpc_message_send_string(message, va_arg(args, char *)); - break; - case RPC_TYPE_ARRAY: { - int i; - int array_type = va_arg(args, int32_t); - int array_size = va_arg(args, uint32_t); - if ((error = rpc_message_send_int32(message, array_type)) < 0) - return error; - if ((error = rpc_message_send_uint32(message, array_size)) < 0) - return error; - switch (array_type) { - case RPC_TYPE_CHAR: { - unsigned char *array = va_arg(args, unsigned char *); - error = rpc_message_flush(message); - if (error != RPC_ERROR_NO_ERROR) - return error; - error = _rpc_message_send_bytes(message, array, array_size); - break; - } - case RPC_TYPE_BOOLEAN: - case RPC_TYPE_INT32: { - int32_t *array = va_arg(args, int32_t *); - for (i = 0; i < array_size; i++) { - if ((error = rpc_message_send_int32(message, array[i])) < 0) - break; - } - break; - } - case RPC_TYPE_UINT32: { - uint32_t *array = va_arg(args, uint32_t *); - for (i = 0; i < array_size; i++) { - if ((error = rpc_message_send_uint32(message, array[i])) < 0) - break; - } - break; - } - case RPC_TYPE_STRING: { - char **array = va_arg(args, char **); - for (i = 0; i < array_size; i++) { - if ((error = rpc_message_send_string(message, array[i])) < 0) - break; - } - break; - } - default: - if ((desc = rpc_message_find_descriptor(array_type)) != NULL) { - uint8_t *array = va_arg(args, uint8_t *); - for (i = 0; i < array_size; i++) { - if ((error = desc->send_callback(message, &array[i * desc->size])) < 0) - break; - } - } - else { - fprintf(stderr, "unknown array arg type %d to send\n", type); - error = RPC_ERROR_MESSAGE_ARGUMENT_UNKNOWN; - } - break; - } - break; - } - default: - if ((desc = rpc_message_find_descriptor(type)) != NULL) - error = desc->send_callback(message, va_arg(args, uint8_t *)); - else { - fprintf(stderr, "unknown arg type %d to send\n", type); - error = RPC_ERROR_MESSAGE_ARGUMENT_UNKNOWN; - } - break; - } - if (error != RPC_ERROR_NO_ERROR) - return error; - } - return RPC_ERROR_NO_ERROR; -} - -// Receive raw BYTES -static inline int _rpc_message_recv_bytes(rpc_message_t *message, unsigned char *bytes, int count) -{ - do { - int n = recv(message->socket, bytes, count, 0); - if (n > 0) { - count -= n; - bytes += n; - } - else if (n == -1 && errno == EINTR) - continue; - else { -#if NON_BLOCKING_IO - if (errno == EAGAIN || errno == EWOULDBLOCK) { - // wait for data to arrive - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(message->socket, &rfds); - int ret = select(message->socket + 1, &rfds, NULL, NULL, NULL); - if (ret > 0) - continue; - } -#endif - return RPC_ERROR_ERRNO_SET; - } - } while (count > 0); - return RPC_ERROR_NO_ERROR; -} - -int rpc_message_recv_bytes(rpc_message_t *message, unsigned char *bytes, int count) -{ - return _rpc_message_recv_bytes(message, bytes, count); -} - -// Receive CHAR -int rpc_message_recv_char(rpc_message_t *message, char *ret) -{ - char r_value; - int error; - if ((error = _rpc_message_recv_bytes(message, (unsigned char *)&r_value, sizeof(r_value))) < 0) - return error; - *ret = r_value; - D(bug(" recv CHAR '%c'\n", *ret)); - return RPC_ERROR_NO_ERROR; -} - -// Receive INT32 -int rpc_message_recv_int32(rpc_message_t *message, int32_t *ret) -{ - int32_t r_value; - int error; - if ((error = _rpc_message_recv_bytes(message, (unsigned char *)&r_value, sizeof(r_value))) < 0) - return error; - *ret = ntohl(r_value); - D(bug(" recv INT32 %d\n", *ret)); - return RPC_ERROR_NO_ERROR; -} - -// Receive UINT32 -int rpc_message_recv_uint32(rpc_message_t *message, uint32_t *ret) -{ - uint32_t r_value; - int error; - if ((error = _rpc_message_recv_bytes(message, (unsigned char *)&r_value, sizeof(r_value))) < 0) - return error; - *ret = ntohl(r_value); - D(bug(" recv UINT32 %u\n", *ret)); - return RPC_ERROR_NO_ERROR; -} - -// Receive STRING -int rpc_message_recv_string(rpc_message_t *message, char **ret) -{ - char *str; - int length; - uint32_t r_value; - int error; - if ((error = _rpc_message_recv_bytes(message, (unsigned char *)&r_value, sizeof(r_value))) < 0) - return error; - length = ntohl(r_value); - if (length == 0) { - str = NULL; - } else { - if ((str = (char *)malloc(length + 1)) == NULL) - return RPC_ERROR_NO_MEMORY; - if ((error = _rpc_message_recv_bytes(message, (unsigned char *)str, length)) < 0) { - free(str); - return error; - } - str[length] = '\0'; - } - *ret = str; - D(bug(" recv STRING \"%s\"\n", *ret)); - return RPC_ERROR_NO_ERROR; -} - -// Receive message arguments -static int rpc_message_recv_args(rpc_message_t *message, va_list args) -{ - int expected_type, error; - rpc_message_descriptor_t *desc; - - while ((expected_type = va_arg(args, int)) != RPC_TYPE_INVALID) { - void *p_value = va_arg(args, void *); - int32_t type; - if ((error = rpc_message_recv_int32(message, &type)) < 0) - return error; - if (type != expected_type) - return RPC_ERROR_MESSAGE_ARGUMENT_MISMATCH; - switch (type) { - case RPC_TYPE_CHAR: - error = rpc_message_recv_char(message, (char *)p_value); - break; - case RPC_TYPE_BOOLEAN: - case RPC_TYPE_INT32: - error = rpc_message_recv_int32(message, (int32_t *)p_value); - break; - case RPC_TYPE_UINT32: - error = rpc_message_recv_uint32(message, (uint32_t *)p_value); - break; - case RPC_TYPE_STRING: - error = rpc_message_recv_string(message, (char **)p_value); - break; - case RPC_TYPE_ARRAY: { - int i; - int32_t array_type; - uint32_t array_size; - if ((error = rpc_message_recv_int32(message, &array_type)) < 0) - return error; - if ((error = rpc_message_recv_uint32(message, &array_size)) < 0) - return error; - p_value = va_arg(args, void *); - *((uint32_t *)p_value) = array_size; - p_value = va_arg(args, void *); - switch (array_type) { - case RPC_TYPE_CHAR: { - unsigned char *array; - if ((array = (unsigned char *)malloc(array_size * sizeof(*array))) == NULL) - return RPC_ERROR_NO_MEMORY; - error = _rpc_message_recv_bytes(message, array, array_size); - if (error != RPC_ERROR_NO_ERROR) { - free(array); - return error; - } - *((void **)p_value) = (void *)array; - break; - } - case RPC_TYPE_BOOLEAN: - case RPC_TYPE_INT32: { - int *array; - if ((array = (int *)malloc(array_size * sizeof(*array))) == NULL) - return RPC_ERROR_NO_MEMORY; - for (i = 0; i < array_size; i++) { - int32_t value; - if ((error = rpc_message_recv_int32(message, &value)) < 0) { - free(array); - return error; - } - array[i] = value; - } - *((void **)p_value) = (void *)array; - break; - } - case RPC_TYPE_UINT32: { - unsigned int *array; - if ((array = (unsigned int *)malloc(array_size * sizeof(*array))) == NULL) - return RPC_ERROR_NO_MEMORY; - for (i = 0; i < array_size; i++) { - uint32_t value; - if ((error = rpc_message_recv_uint32(message, &value)) < 0) { - free(array); - return error; - } - array[i] = value; - } - *((void **)p_value) = (void *)array; - break; - } - case RPC_TYPE_STRING: { - char **array; - if ((array = (char **)malloc(array_size * sizeof(*array))) == NULL) - return RPC_ERROR_NO_MEMORY; - for (i = 0; i < array_size; i++) { - char *str; - if ((error = rpc_message_recv_string(message, &str)) < 0) { - free(array); - return error; - } - array[i] = str; - } - *((void **)p_value) = (void *)array; - break; - } - default: - if ((desc = rpc_message_find_descriptor(array_type)) != NULL) { - char *array; - if ((array = (char *)malloc(array_size * desc->size)) == NULL) - return RPC_ERROR_NO_MEMORY; - for (i = 0; i < array_size; i++) { - if ((error = desc->recv_callback(message, &array[i * desc->size])) < 0) { - free(array); - return error; - } - } - *((void **)p_value) = array; - } - else { - fprintf(stderr, "unknown array arg type %d to receive\n", type); - error = RPC_ERROR_MESSAGE_ARGUMENT_UNKNOWN; - } - break; - } - break; - } - default: - if ((desc = rpc_message_find_descriptor(type)) != NULL) - error = desc->recv_callback(message, p_value); - else { - fprintf(stderr, "unknown arg type %d to send\n", type); - error = RPC_ERROR_MESSAGE_ARGUMENT_UNKNOWN; - } - break; - } - if (error != RPC_ERROR_NO_ERROR) - return error; - } - return RPC_ERROR_NO_ERROR; -} - -// Skip message argument -static int rpc_message_skip_arg(rpc_message_t *message, int type) -{ - unsigned char dummy[BUFSIZ]; - int error = RPC_ERROR_GENERIC; - switch (type) { - case RPC_TYPE_CHAR: - error = _rpc_message_recv_bytes(message, dummy, 1); - break; - case RPC_TYPE_BOOLEAN: - case RPC_TYPE_INT32: - case RPC_TYPE_UINT32: - error = _rpc_message_recv_bytes(message, dummy, 4); - break; - case RPC_TYPE_STRING: { - int32_t length; - if ((error = rpc_message_recv_int32(message, &length)) < 0) - return error; - while (length >= sizeof(dummy)) { - if ((error = _rpc_message_recv_bytes(message, dummy, sizeof(dummy))) < 0) - return error; - length -= sizeof(dummy); - } - if (length > 0) { - if ((error = _rpc_message_recv_bytes(message, dummy, length)) < 0) - return error; - } - break; - } - default: - fprintf(stderr, "unknown arg type %d to receive\n", type); - break; - } - return error; -} - -// Dispatch message received in the server loop -int rpc_dispatch(rpc_connection_t *connection) -{ - rpc_message_t message; - rpc_message_init(&message, connection); - - int32_t method, value, ret = RPC_MESSAGE_FAILURE; - if (rpc_message_recv_int32(&message, &value) != RPC_ERROR_NO_ERROR || - value != RPC_MESSAGE_START) - return ret; - - D(bug("receiving message\n")); - if (rpc_message_recv_int32(&message, &method) == RPC_ERROR_NO_ERROR && - connection->callbacks != NULL) { - int i; - for (i = 0; i < connection->n_callbacks; i++) { - if (connection->callbacks[i].id == method) { - if (connection->callbacks[i].callback && - connection->callbacks[i].callback(connection) == RPC_ERROR_NO_ERROR) { - if (rpc_message_recv_int32(&message, &value) == RPC_ERROR_NO_ERROR && value == RPC_MESSAGE_END) - ret = RPC_MESSAGE_ACK; - else { - fprintf(stderr, "corrupted message handler %d\n", method); - for (;;) { - if (rpc_message_skip_arg(&message, value) != RPC_ERROR_NO_ERROR) - break; - if (rpc_message_recv_int32(&message, &value) != RPC_ERROR_NO_ERROR) - break; - if (value == RPC_MESSAGE_END) - break; - } - } - break; - } - } - } - } - rpc_message_send_int32(&message, ret); - rpc_message_flush(&message); - D(bug(" -- message received\n")); - return ret == RPC_MESSAGE_ACK ? method : ret; -} - - -/* ====================================================================== */ -/* === Method Callbacks Handling === */ -/* ====================================================================== */ - -// Add a user-defined method callback (server side) -static int rpc_method_add_callback(rpc_connection_t *connection, const rpc_method_descriptor_t *desc) -{ - const int N_ENTRIES_ALLOC = 8; - int i; - - // pre-allocate up to N_ENTRIES_ALLOC entries - if (connection->callbacks == NULL) { - if ((connection->callbacks = (rpc_method_descriptor_t *)calloc(N_ENTRIES_ALLOC, sizeof(connection->callbacks[0]))) == NULL) - return RPC_ERROR_NO_MEMORY; - connection->n_callbacks = N_ENTRIES_ALLOC; - } - - // look for a free slot - for (i = connection->n_callbacks - 1; i >= 0; i--) { - if (connection->callbacks[i].callback == NULL) - break; - } - - // none found, reallocate - if (i < 0) { - if ((connection->callbacks = (rpc_method_descriptor_t *)realloc(connection->callbacks, (connection->n_callbacks + N_ENTRIES_ALLOC) * sizeof(connection->callbacks[0]))) == NULL) - return RPC_ERROR_NO_MEMORY; - i = connection->n_callbacks; - memset(&connection->callbacks[i], 0, N_ENTRIES_ALLOC * sizeof(connection->callbacks[0])); - connection->n_callbacks += N_ENTRIES_ALLOC; - } - - D(bug("rpc_method_add_callback for method %d in slot %d\n", desc->id, i)); - connection->callbacks[i] = *desc; - return RPC_ERROR_NO_ERROR; -} - -// Add user-defined method callbacks (server side) -int rpc_method_add_callbacks(rpc_connection_t *connection, const rpc_method_descriptor_t *descs, int n_descs) -{ - D(bug("rpc_method_add_callbacks\n")); - - if (connection == NULL) - return RPC_ERROR_CONNECTION_NULL; - if (connection->type != RPC_CONNECTION_SERVER) - return RPC_ERROR_CONNECTION_TYPE_MISMATCH; - - while (--n_descs >= 0) { - int error = rpc_method_add_callback(connection, &descs[n_descs]); - if (error != RPC_ERROR_NO_ERROR) - return error; - } - - return RPC_ERROR_NO_ERROR; -} - -// Remove a user-defined method callback (common code) -int rpc_method_remove_callback_id(rpc_connection_t *connection, int id) -{ - D(bug("rpc_method_remove_callback_id\n")); - - if (connection->callbacks) { - int i; - for (i = 0; i < connection->n_callbacks; i++) { - if (connection->callbacks[i].id == id) { - connection->callbacks[i].callback = NULL; - return RPC_ERROR_NO_ERROR; - } - } - } - - return RPC_ERROR_GENERIC; -} - -// Remove user-defined method callbacks (server side) -int rpc_method_remove_callbacks(rpc_connection_t *connection, const rpc_method_descriptor_t *callbacks, int n_callbacks) -{ - D(bug("rpc_method_remove_callbacks\n")); - - if (connection == NULL) - return RPC_ERROR_CONNECTION_NULL; - if (connection->type != RPC_CONNECTION_SERVER) - return RPC_ERROR_CONNECTION_TYPE_MISMATCH; - - while (--n_callbacks >= 0) { - int error = rpc_method_remove_callback_id(connection, callbacks[n_callbacks].id); - if (error != RPC_ERROR_NO_ERROR) - return error; - } - - return RPC_ERROR_NO_ERROR; -} - - -/* ====================================================================== */ -/* === Remote Procedure Call (method invocation) === */ -/* ====================================================================== */ - -// Invoke remote procedure (client side) -int rpc_method_invoke(rpc_connection_t *connection, int method, ...) -{ - D(bug("rpc_method_invoke method=%d\n", method)); - - rpc_message_t message; - int error; - va_list args; - - if (connection == NULL) - return RPC_ERROR_CONNECTION_NULL; - if (connection->type != RPC_CONNECTION_CLIENT) - return RPC_ERROR_CONNECTION_TYPE_MISMATCH; - - rpc_message_init(&message, connection); - error = rpc_message_send_int32(&message, RPC_MESSAGE_START); - if (error != RPC_ERROR_NO_ERROR) - return error; - error = rpc_message_send_int32(&message, method); - if (error != RPC_ERROR_NO_ERROR) - return error; - va_start(args, method); - error = rpc_message_send_args(&message, args); - va_end(args); - if (error != RPC_ERROR_NO_ERROR) - return error; - error = rpc_message_send_int32(&message, RPC_MESSAGE_END); - if (error != RPC_ERROR_NO_ERROR) - return error; - error = rpc_message_flush(&message); - if (error != RPC_ERROR_NO_ERROR) - return error; - return RPC_ERROR_NO_ERROR; -} - -// Retrieve procedure arguments (server side) -int rpc_method_get_args(rpc_connection_t *connection, ...) -{ - D(bug("rpc_method_get_args\n")); - - int error; - va_list args; - rpc_message_t message; - - if (connection == NULL) - return RPC_ERROR_CONNECTION_NULL; - if (connection->type != RPC_CONNECTION_SERVER) - return RPC_ERROR_CONNECTION_TYPE_MISMATCH; - - rpc_message_init(&message, connection); - va_start(args, connection); - error = rpc_message_recv_args(&message, args); - va_end(args); - - return error; -} - -// Wait for a reply from the remote procedure (client side) -int rpc_method_wait_for_reply(rpc_connection_t *connection, ...) -{ - D(bug("rpc_method_wait_for_reply\n")); - - int error, type; - int32_t ret; - va_list args; - rpc_message_t message; - - if (connection == NULL) - return RPC_ERROR_CONNECTION_NULL; - if (connection->type != RPC_CONNECTION_CLIENT) - return RPC_ERROR_CONNECTION_TYPE_MISMATCH; - - rpc_connection_set_status(connection, RPC_STATUS_BUSY); - - rpc_message_init(&message, connection); - va_start(args, connection); - type = va_arg(args, int); - va_end(args); - - if (type != RPC_TYPE_INVALID) { - error = rpc_message_recv_int32(&message, &ret); - if (error != RPC_ERROR_NO_ERROR) - return_error(error); - if (ret != RPC_MESSAGE_REPLY) { - D(bug("TRUNCATED 1 [%d]\n", ret)); - return_error(RPC_ERROR_MESSAGE_TRUNCATED); - } - va_start(args, connection); - error = rpc_message_recv_args(&message, args); - va_end(args); - if (error != RPC_ERROR_NO_ERROR) - return_error(error); - error = rpc_message_recv_int32(&message, &ret); - if (error != RPC_ERROR_NO_ERROR) - return_error(error); - if (ret != RPC_MESSAGE_END) { - D(bug("TRUNCATED 2 [%d]\n", ret)); - return_error(RPC_ERROR_MESSAGE_TRUNCATED); - } - } - - error = rpc_message_recv_int32(&message, &ret); - if (error != RPC_ERROR_NO_ERROR) - return_error(error); - if (ret != RPC_MESSAGE_ACK) { - D(bug("TRUNCATED 3 [%d]\n", ret)); - return_error(RPC_ERROR_MESSAGE_TRUNCATED); - } - - return_error(RPC_ERROR_NO_ERROR); - - do_return: - rpc_connection_set_status(connection, RPC_STATUS_IDLE); - return error; -} - -// Send a reply to the client (server side) -int rpc_method_send_reply(rpc_connection_t *connection, ...) -{ - D(bug("rpc_method_send_reply\n")); - - rpc_message_t message; - int error; - va_list args; - - if (connection == NULL) - return RPC_ERROR_GENERIC; - if (connection->type != RPC_CONNECTION_SERVER) - return RPC_ERROR_GENERIC; - - rpc_message_init(&message, connection); - error = rpc_message_send_int32(&message, RPC_MESSAGE_REPLY); - if (error != RPC_ERROR_NO_ERROR) - return error; - va_start(args, connection); - error = rpc_message_send_args(&message, args); - va_end(args); - if (error != RPC_ERROR_NO_ERROR) - return error; - error = rpc_message_send_int32(&message, RPC_MESSAGE_END); - if (error != RPC_ERROR_NO_ERROR) - return error; - error = rpc_message_flush(&message); - if (error != RPC_ERROR_NO_ERROR) - return error; - return RPC_ERROR_NO_ERROR; -} diff --git a/BasiliskII/src/Unix/semaphore.h b/BasiliskII/src/Unix/semaphore.h deleted file mode 100644 index fc9954f9..00000000 --- a/BasiliskII/src/Unix/semaphore.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef __SEMAPHORE_H -#define __SEMAPHORE_H - -#define SEM_VALUE_MAX 64 - -#if defined(c_plusplus) || defined(__cplusplus) -extern "C" { -#endif /* c_plusplus || __cplusplus */ - -/* MacOS X doesn't implement unnamed POSIX semaphores, event though - the libc defines them! */ -#if (defined(__MACH__) && defined(__APPLE__)) -#include -#include -#include - -#define sem_t semaphore_t -#define sem_init(SEM,UNUSED,VALUE) semaphore_create(current_task(), (SEM), SYNC_POLICY_FIFO, (VALUE)) -#define sem_destroy(SEM) semaphore_destroy(current_task(), *(SEM)) -#define sem_wait(SEM) semaphore_wait(*(SEM)) -#define sem_post(SEM) semaphore_signal(*(SEM)) -#else -typedef struct psem { - pthread_mutex_t sem_lock; - int sem_value; - int sem_waiting; -} sem_t; - -int sem_init(sem_t* sem, int pshared, unsigned int value); -int sem_destroy(sem_t* sem); -sem_t sem_open(const char* name, int oflag, ...); -int sem_close(sem_t* sem); -int sem_unlink(const char* name); -int sem_wait(sem_t* sem); -int sem_trywait(sem_t* sem); -int sem_post(sem_t* sem); -int sem_getvalue(sem_t* sem, int* sval); -#endif - -#if defined(c_plusplus) || defined(__cplusplus) -}; -#endif /* c_plusplus || __cplusplus */ - -#endif /* __SEMAPHORE_H */