2837d9ed43
We're going to need these for next code I'm going to send out for review: support for poll() and kqueue() on CloudABI.
256 lines
9.9 KiB
C
256 lines
9.9 KiB
C
// Copyright (c) 2015 Nuxi, https://nuxi.nl/
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions
|
|
// are met:
|
|
// 1. Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// 2. Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
// SUCH DAMAGE.
|
|
|
|
// Machine dependent definitions.
|
|
|
|
// Macro to force sane alignment rules.
|
|
//
|
|
// On x86-32 it is the case that 64-bit integers are 4-byte aligned when
|
|
// embedded in structs, even though they are 8-byte aligned when not
|
|
// embedded. Force 8-byte alignment explicitly.
|
|
#define MEMBER(type) alignas(alignof(type)) type
|
|
#define ASSERT_OFFSET(type, field, offset32, offset64) \
|
|
static_assert((sizeof(PTR(void)) == 4 && \
|
|
offsetof(IDENT(type), field) == (offset32)) || \
|
|
(sizeof(PTR(void)) == 8 && \
|
|
offsetof(IDENT(type), field) == (offset64)), \
|
|
"Offset incorrect")
|
|
#define ASSERT_SIZE(type, size32, size64) \
|
|
static_assert( \
|
|
(sizeof(PTR(void)) == 4 && sizeof(IDENT(type)) == (size32)) || \
|
|
(sizeof(PTR(void)) == 8 && sizeof(IDENT(type)) == (size64)), \
|
|
"Size incorrect")
|
|
|
|
typedef void IDENT(threadentry_t)(cloudabi_tid_t, PTR(void));
|
|
|
|
// Auxiliary vector entry, used to provide paramters on startup.
|
|
typedef struct {
|
|
uint32_t a_type;
|
|
union {
|
|
MEMBER(IDENT(size_t)) a_val;
|
|
MEMBER(PTR(void)) a_ptr;
|
|
};
|
|
} IDENT(auxv_t);
|
|
ASSERT_OFFSET(auxv_t, a_type, 0, 0);
|
|
ASSERT_OFFSET(auxv_t, a_val, 4, 8);
|
|
ASSERT_OFFSET(auxv_t, a_ptr, 4, 8);
|
|
ASSERT_SIZE(auxv_t, 8, 16);
|
|
|
|
typedef struct {
|
|
MEMBER(PTR(const void)) iov_base;
|
|
MEMBER(IDENT(size_t)) iov_len;
|
|
} IDENT(ciovec_t);
|
|
ASSERT_OFFSET(ciovec_t, iov_base, 0, 0);
|
|
ASSERT_OFFSET(ciovec_t, iov_len, 4, 8);
|
|
ASSERT_SIZE(ciovec_t, 8, 16);
|
|
|
|
typedef struct {
|
|
MEMBER(cloudabi_userdata_t) userdata;
|
|
MEMBER(cloudabi_errno_t) error;
|
|
MEMBER(cloudabi_eventtype_t) type;
|
|
union {
|
|
// CLOUDABI_EVENTTYPE_CLOCK: Wait until the value of a clock
|
|
// exceeds a value.
|
|
struct {
|
|
MEMBER(cloudabi_userdata_t) identifier;
|
|
} clock;
|
|
|
|
// CLOUDABI_EVENTTYPE_CONDVAR: Release a lock and wait on a
|
|
// condition variable.
|
|
struct {
|
|
MEMBER(PTR(_Atomic(cloudabi_condvar_t))) condvar;
|
|
} condvar;
|
|
|
|
// CLOUDABI_EVENTTYPE_FD_READ and CLOUDABI_EVENTTYPE_FD_WRITE:
|
|
// Wait for a file descriptor to allow read() and write() to be
|
|
// called without blocking.
|
|
struct {
|
|
MEMBER(cloudabi_filesize_t) nbytes;
|
|
MEMBER(cloudabi_fd_t) fd;
|
|
MEMBER(uint16_t) flags;
|
|
} fd_readwrite;
|
|
|
|
// CLOUDABI_EVENT_LOCK_RDLOCK and CLOUDABI_EVENT_LOCK_WRLOCK: Wait
|
|
// and acquire a read or write lock.
|
|
struct {
|
|
MEMBER(PTR(_Atomic(cloudabi_lock_t))) lock;
|
|
} lock;
|
|
|
|
// CLOUDABI_EVENTTYPE_PROC_TERMINATE: Wait for a process to terminate.
|
|
struct {
|
|
MEMBER(cloudabi_fd_t) fd;
|
|
MEMBER(cloudabi_signal_t) signal; // Non-zero if process got killed.
|
|
MEMBER(cloudabi_exitcode_t) exitcode; // Exit code.
|
|
} proc_terminate;
|
|
};
|
|
} IDENT(event_t);
|
|
ASSERT_OFFSET(event_t, userdata, 0, 0);
|
|
ASSERT_OFFSET(event_t, error, 8, 8);
|
|
ASSERT_OFFSET(event_t, type, 10, 10);
|
|
ASSERT_OFFSET(event_t, clock.identifier, 16, 16);
|
|
ASSERT_OFFSET(event_t, condvar.condvar, 16, 16);
|
|
ASSERT_OFFSET(event_t, fd_readwrite.nbytes, 16, 16);
|
|
ASSERT_OFFSET(event_t, fd_readwrite.fd, 24, 24);
|
|
ASSERT_OFFSET(event_t, fd_readwrite.flags, 28, 28);
|
|
ASSERT_OFFSET(event_t, lock.lock, 16, 16);
|
|
ASSERT_OFFSET(event_t, proc_terminate.fd, 16, 16);
|
|
ASSERT_OFFSET(event_t, proc_terminate.signal, 20, 20);
|
|
ASSERT_OFFSET(event_t, proc_terminate.exitcode, 24, 24);
|
|
ASSERT_SIZE(event_t, 32, 32);
|
|
|
|
typedef struct {
|
|
MEMBER(PTR(void)) iov_base;
|
|
MEMBER(IDENT(size_t)) iov_len;
|
|
} IDENT(iovec_t);
|
|
ASSERT_OFFSET(iovec_t, iov_base, 0, 0);
|
|
ASSERT_OFFSET(iovec_t, iov_len, 4, 8);
|
|
ASSERT_SIZE(iovec_t, 8, 16);
|
|
|
|
typedef struct {
|
|
MEMBER(PTR(const IDENT(iovec_t))) ri_data; // Data I/O vectors.
|
|
MEMBER(IDENT(size_t)) ri_datalen; // Number of data I/O vectors.
|
|
MEMBER(PTR(cloudabi_fd_t)) ri_fds; // File descriptors.
|
|
MEMBER(IDENT(size_t)) ri_fdslen; // Number of file descriptors.
|
|
MEMBER(cloudabi_msgflags_t) ri_flags; // Input flags.
|
|
} IDENT(recv_in_t);
|
|
ASSERT_OFFSET(recv_in_t, ri_data, 0, 0);
|
|
ASSERT_OFFSET(recv_in_t, ri_datalen, 4, 8);
|
|
ASSERT_OFFSET(recv_in_t, ri_fds, 8, 16);
|
|
ASSERT_OFFSET(recv_in_t, ri_fdslen, 12, 24);
|
|
ASSERT_OFFSET(recv_in_t, ri_flags, 16, 32);
|
|
ASSERT_SIZE(recv_in_t, 20, 40);
|
|
|
|
typedef struct {
|
|
MEMBER(IDENT(size_t)) ro_datalen; // Bytes of data received.
|
|
MEMBER(IDENT(size_t)) ro_fdslen; // Number of file descriptors received.
|
|
MEMBER(cloudabi_sockaddr_t) ro_sockname; // Address of receiver.
|
|
MEMBER(cloudabi_sockaddr_t) ro_peername; // Address of sender.
|
|
MEMBER(cloudabi_msgflags_t) ro_flags; // Output flags.
|
|
} IDENT(recv_out_t);
|
|
ASSERT_OFFSET(recv_out_t, ro_datalen, 0, 0);
|
|
ASSERT_OFFSET(recv_out_t, ro_fdslen, 4, 8);
|
|
ASSERT_OFFSET(recv_out_t, ro_sockname, 8, 16);
|
|
ASSERT_OFFSET(recv_out_t, ro_peername, 28, 36);
|
|
ASSERT_OFFSET(recv_out_t, ro_flags, 48, 56);
|
|
ASSERT_SIZE(recv_out_t, 52, 64);
|
|
|
|
typedef struct {
|
|
MEMBER(PTR(const IDENT(ciovec_t))) si_data; // Data I/O vectors.
|
|
MEMBER(IDENT(size_t)) si_datalen; // Number of data I/O vectors.
|
|
MEMBER(PTR(const cloudabi_fd_t)) si_fds; // File descriptors.
|
|
MEMBER(IDENT(size_t)) si_fdslen; // Number of file descriptors.
|
|
MEMBER(cloudabi_msgflags_t) si_flags; // Input flags.
|
|
} IDENT(send_in_t);
|
|
ASSERT_OFFSET(send_in_t, si_data, 0, 0);
|
|
ASSERT_OFFSET(send_in_t, si_datalen, 4, 8);
|
|
ASSERT_OFFSET(send_in_t, si_fds, 8, 16);
|
|
ASSERT_OFFSET(send_in_t, si_fdslen, 12, 24);
|
|
ASSERT_OFFSET(send_in_t, si_flags, 16, 32);
|
|
ASSERT_SIZE(send_in_t, 20, 40);
|
|
|
|
typedef struct {
|
|
MEMBER(IDENT(size_t)) so_datalen; // Bytes of data sent.
|
|
} IDENT(send_out_t);
|
|
ASSERT_OFFSET(send_out_t, so_datalen, 0, 0);
|
|
ASSERT_SIZE(send_out_t, 4, 8);
|
|
|
|
typedef struct {
|
|
MEMBER(cloudabi_userdata_t) userdata;
|
|
MEMBER(uint16_t) flags;
|
|
MEMBER(cloudabi_eventtype_t) type;
|
|
union {
|
|
// CLOUDABI_EVENTTYPE_CLOCK: Wait until the value of a clock
|
|
// exceeds a value.
|
|
struct {
|
|
MEMBER(cloudabi_userdata_t) identifier;
|
|
MEMBER(cloudabi_clockid_t) clock_id;
|
|
MEMBER(cloudabi_timestamp_t) timeout;
|
|
MEMBER(cloudabi_timestamp_t) precision;
|
|
MEMBER(uint16_t) flags;
|
|
} clock;
|
|
|
|
// CLOUDABI_EVENTTYPE_CONDVAR: Release a lock and wait on a
|
|
// condition variable.
|
|
struct {
|
|
MEMBER(PTR(_Atomic(cloudabi_condvar_t))) condvar;
|
|
MEMBER(PTR(_Atomic(cloudabi_lock_t))) lock;
|
|
MEMBER(cloudabi_mflags_t) condvar_scope;
|
|
MEMBER(cloudabi_mflags_t) lock_scope;
|
|
} condvar;
|
|
|
|
// CLOUDABI_EVENTTYPE_FD_READ and CLOUDABI_EVENTTYPE_FD_WRITE:
|
|
// Wait for a file descriptor to allow read() and write() to be
|
|
// called without blocking.
|
|
struct {
|
|
MEMBER(cloudabi_fd_t) fd;
|
|
MEMBER(uint16_t) flags;
|
|
} fd_readwrite;
|
|
|
|
// CLOUDABI_EVENT_LOCK_RDLOCK and CLOUDABI_EVENT_LOCK_WRLOCK: Wait
|
|
// and acquire a read or write lock.
|
|
struct {
|
|
MEMBER(PTR(_Atomic(cloudabi_lock_t))) lock;
|
|
MEMBER(cloudabi_mflags_t) lock_scope;
|
|
} lock;
|
|
|
|
// CLOUDABI_EVENTTYPE_PROC_TERMINATE: Wait for a process to terminate.
|
|
struct {
|
|
MEMBER(cloudabi_fd_t) fd;
|
|
} proc_terminate;
|
|
};
|
|
} IDENT(subscription_t);
|
|
ASSERT_OFFSET(subscription_t, userdata, 0, 0);
|
|
ASSERT_OFFSET(subscription_t, flags, 8, 8);
|
|
ASSERT_OFFSET(subscription_t, type, 10, 10);
|
|
ASSERT_OFFSET(subscription_t, clock.identifier, 16, 16);
|
|
ASSERT_OFFSET(subscription_t, clock.clock_id, 24, 24);
|
|
ASSERT_OFFSET(subscription_t, clock.timeout, 32, 32);
|
|
ASSERT_OFFSET(subscription_t, clock.precision, 40, 40);
|
|
ASSERT_OFFSET(subscription_t, clock.flags, 48, 48);
|
|
ASSERT_OFFSET(subscription_t, condvar.condvar, 16, 16);
|
|
ASSERT_OFFSET(subscription_t, condvar.lock, 20, 24);
|
|
ASSERT_OFFSET(subscription_t, condvar.condvar_scope, 24, 32);
|
|
ASSERT_OFFSET(subscription_t, condvar.lock_scope, 25, 33);
|
|
ASSERT_OFFSET(subscription_t, fd_readwrite.fd, 16, 16);
|
|
ASSERT_OFFSET(subscription_t, fd_readwrite.flags, 20, 20);
|
|
ASSERT_OFFSET(subscription_t, lock.lock, 16, 16);
|
|
ASSERT_OFFSET(subscription_t, lock.lock_scope, 20, 24);
|
|
ASSERT_OFFSET(subscription_t, proc_terminate.fd, 16, 16);
|
|
ASSERT_SIZE(subscription_t, 56, 56);
|
|
|
|
typedef struct {
|
|
MEMBER(PTR(IDENT(threadentry_t))) entry_point; // Entry point.
|
|
MEMBER(PTR(void)) stack; // Pointer to stack buffer.
|
|
MEMBER(IDENT(size_t)) stack_size; // Size of stack buffer.
|
|
MEMBER(PTR(void)) argument; // Argument to be passed to entry point.
|
|
} IDENT(threadattr_t);
|
|
ASSERT_OFFSET(threadattr_t, entry_point, 0, 0);
|
|
ASSERT_OFFSET(threadattr_t, stack, 4, 8);
|
|
ASSERT_OFFSET(threadattr_t, stack_size, 8, 16);
|
|
ASSERT_OFFSET(threadattr_t, argument, 12, 24);
|
|
ASSERT_SIZE(threadattr_t, 16, 32);
|
|
|
|
#undef MEMBER
|
|
#undef ASSERT_OFFSET
|
|
#undef ASSERT_SIZE
|