Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e8e19e4bc | ||
|
|
a15af5b486 | ||
|
|
5a22d6f322 | ||
|
|
86a9a26fde | ||
|
|
b53d0a29fe | ||
|
|
1bc011c83a | ||
|
|
9967411f02 | ||
|
|
6827ebaf18 | ||
|
|
4788e0eef7 | ||
|
|
43725ee34a | ||
|
|
7d03e805d8 | ||
|
|
052e4c5e5d | ||
|
|
d808a81cd9 | ||
|
|
5f48ee01b6 | ||
|
|
3d4da9f841 | ||
|
|
d829d94d8d | ||
|
|
d5d9d4fe82 | ||
|
|
2c3852d9e6 |
@@ -14,3 +14,5 @@ tmp.*
|
||||
*.testdata
|
||||
*.sqlite3
|
||||
*.db
|
||||
*.elf
|
||||
*.dbg
|
||||
@@ -48,7 +48,7 @@ concurrency models like async/await.
|
||||
|
||||
## Using
|
||||
|
||||
Just drop the "neco.c" and "neco.h" files into your project. Uses standard C11 so most modern C compilers should work.
|
||||
Just drop the "neco.c" and "neco.h" files into your project. Most modern C compilers should work.
|
||||
|
||||
```sh
|
||||
cc -c neco.c
|
||||
|
||||
Vendored
+4
-2
@@ -1,2 +1,4 @@
|
||||
import github.com/tidwall/sco v0.1.0
|
||||
import github.com/tidwall/stack v0.1.0
|
||||
import github.com/tidwall/sco v0.2.1
|
||||
|
||||
sum 9610203b4ce6f6e3cac862a3deb99cb418acac7c sco.c
|
||||
sum 92baa4119d14dbb2b1effcd2eaeb4adcba8befc1 sco.h
|
||||
|
||||
Vendored
+12
-7
@@ -135,6 +135,11 @@ static void llco_exit(void) {
|
||||
#error LLCO_ASM must not be defined
|
||||
#endif
|
||||
|
||||
#if defined(__COSMOCC__) && !defined(LLCO_NOASM)
|
||||
// Cosmopolitan has issues with asm code
|
||||
#define LLCO_NOASM
|
||||
#endif
|
||||
|
||||
// Passing the entry function into assembly requires casting the function
|
||||
// pointer to an object pointer, which is forbidden in the ISO C spec but
|
||||
// allowed in posix. Ignore the warning attributed to this requirement when
|
||||
@@ -1169,7 +1174,7 @@ const char *llco_method(void *caps) {
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && !defined(__EMSCRIPTEN__) && !defined(_WIN32) && \
|
||||
!defined(LLCO_NOUNWIND)
|
||||
!defined(LLCO_NOUNWIND) && !defined(__COSMOCC__)
|
||||
|
||||
#include <unwind.h>
|
||||
#include <string.h>
|
||||
@@ -1182,7 +1187,7 @@ struct llco_dlinfo {
|
||||
void *dli_saddr; /* Address of nearest symbol */
|
||||
};
|
||||
|
||||
#ifdef __linux__
|
||||
#if defined(__linux__) && !defined(_GNU_SOURCE)
|
||||
int dladdr(const void *, void *);
|
||||
#endif
|
||||
|
||||
@@ -1853,11 +1858,11 @@ static void sco_entry(void *udata) {
|
||||
co->prev = co;
|
||||
co->next = co;
|
||||
if (sco_cur) {
|
||||
// Reschedule the coroutine that started this one
|
||||
sco_list_push_back(&sco_yielders, co);
|
||||
sco_list_push_back(&sco_yielders, sco_cur);
|
||||
sco_nyielders += 2;
|
||||
sco_switch(false, false);
|
||||
// Reschedule the coroutine that started this one immediately after
|
||||
// all running coroutines, but before any yielding coroutines, and
|
||||
// continue running the started coroutine.
|
||||
sco_list_push_back(&sco_runners, sco_cur);
|
||||
sco_nrunners++;
|
||||
}
|
||||
sco_cur = co;
|
||||
if (sco_user_entry) {
|
||||
|
||||
Vendored
+9
@@ -12,6 +12,12 @@
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef WORKER_STATIC
|
||||
#define WORKER_API static
|
||||
#else
|
||||
#define WORKER_API
|
||||
#endif
|
||||
|
||||
#define WORKER_DEF_TIMEOUT INT64_C(1000000000) // one second
|
||||
#define WORKER_DEF_MAX_THREADS 2
|
||||
#define WORKER_DEF_MAX_THREAD_ENTRIES 32
|
||||
@@ -46,6 +52,7 @@ struct worker {
|
||||
void (*free)(void*);
|
||||
};
|
||||
|
||||
WORKER_API
|
||||
void worker_free(struct worker *worker) {
|
||||
if (worker) {
|
||||
if (worker->threads) {
|
||||
@@ -70,6 +77,7 @@ void worker_free(struct worker *worker) {
|
||||
}
|
||||
}
|
||||
|
||||
WORKER_API
|
||||
struct worker *worker_new(struct worker_opts *opts) {
|
||||
// Load options
|
||||
int nthreads = opts ? opts->max_threads : 0;
|
||||
@@ -164,6 +172,7 @@ static void *worker_entry(void *arg) {
|
||||
/// @param udata any user data
|
||||
/// @return true for success or false if no worker is available.
|
||||
/// @return false for invalid arguments. Worker and work must no be null.
|
||||
WORKER_API
|
||||
bool worker_submit(struct worker *worker, int64_t pin, void(*work)(void *udata),
|
||||
void *udata)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// Port scanning
|
||||
//
|
||||
// Thanks to @sigidagi for recommending this example.
|
||||
// See https://github.com/tidwall/neco/issues/14
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "../neco.h"
|
||||
|
||||
void co_dial_port(int argc, void** argv) {
|
||||
const char *host = argv[0]; // host
|
||||
int port = *(int*)argv[1]; // port
|
||||
neco_waitgroup *wg = argv[2]; // waitgroup
|
||||
|
||||
// Dial the port with a one second deadline
|
||||
char addr[256];
|
||||
snprintf(addr, sizeof(addr), "%s:%d", host, port);
|
||||
int fd = neco_dial_dl("tcp", addr, neco_now() + NECO_SECOND);
|
||||
if (fd < 0) {
|
||||
printf("%-5d FAIL\t%s\n", port, neco_strerror(neco_lasterr()));
|
||||
} else {
|
||||
printf("%-5d OK\n", port);
|
||||
close(fd);
|
||||
}
|
||||
// Notify the waitgroup that we are done.
|
||||
neco_waitgroup_done(wg);
|
||||
}
|
||||
|
||||
int neco_main(int argc, char** argv) {
|
||||
const char *host = "scanme.nmap.org";
|
||||
int ports[] = { 22, 80, 8080, 443 };
|
||||
|
||||
|
||||
// Use a waitgroup to synchronize the coroutines
|
||||
neco_waitgroup wg;
|
||||
neco_waitgroup_init(&wg);
|
||||
|
||||
// Dial all the ports
|
||||
printf("%s\n", host);
|
||||
for (int i = 0; i < sizeof(ports)/sizeof(int); i++) {
|
||||
neco_waitgroup_add(&wg, 1);
|
||||
neco_start(co_dial_port, 3, host, &ports[i], &wg);
|
||||
}
|
||||
|
||||
// Wait for all coroutines to finish
|
||||
neco_waitgroup_wait(&wg);
|
||||
return 0;
|
||||
}
|
||||
@@ -97,8 +97,15 @@ NECO_NOWRITEWORKERS // Disable all write workers
|
||||
#undef NECO_BURST
|
||||
#define NECO_BURST 1
|
||||
#endif
|
||||
#if NECO_MAXWORKERS > 8
|
||||
#undef NECO_MAXWORKERS
|
||||
#define NECO_MAXWORKERS 8
|
||||
#endif
|
||||
#if NECO_MAXRINGSIZE > 4
|
||||
#undef NECO_MAXRINGSIZE
|
||||
#define NECO_MAXRINGSIZE 4
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// The following is only needed when LLCO_NOASM or LLCO_STACKJMP is defined.
|
||||
// This same block is duplicated in the llco.c block below.
|
||||
@@ -137,6 +144,7 @@ NECO_NOWRITEWORKERS // Disable all write workers
|
||||
|
||||
#define SCO_STATIC
|
||||
#define STACK_STATIC
|
||||
#define WORKER_STATIC
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
@@ -281,6 +289,11 @@ static void llco_exit(void) {
|
||||
#error LLCO_ASM must not be defined
|
||||
#endif
|
||||
|
||||
#if defined(__COSMOCC__) && !defined(LLCO_NOASM)
|
||||
// Cosmopolitan has issues with asm code
|
||||
#define LLCO_NOASM
|
||||
#endif
|
||||
|
||||
// Passing the entry function into assembly requires casting the function
|
||||
// pointer to an object pointer, which is forbidden in the ISO C spec but
|
||||
// allowed in posix. Ignore the warning attributed to this requirement when
|
||||
@@ -1315,7 +1328,7 @@ const char *llco_method(void *caps) {
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && !defined(__EMSCRIPTEN__) && !defined(_WIN32) && \
|
||||
!defined(LLCO_NOUNWIND)
|
||||
!defined(LLCO_NOUNWIND) && !defined(__COSMOCC__)
|
||||
|
||||
#include <unwind.h>
|
||||
#include <string.h>
|
||||
@@ -1328,7 +1341,7 @@ struct llco_dlinfo {
|
||||
void *dli_saddr; /* Address of nearest symbol */
|
||||
};
|
||||
|
||||
#ifdef __linux__
|
||||
#if defined(__linux__) && !defined(_GNU_SOURCE)
|
||||
int dladdr(const void *, void *);
|
||||
#endif
|
||||
|
||||
@@ -1999,11 +2012,11 @@ static void sco_entry(void *udata) {
|
||||
co->prev = co;
|
||||
co->next = co;
|
||||
if (sco_cur) {
|
||||
// Reschedule the coroutine that started this one
|
||||
sco_list_push_back(&sco_yielders, co);
|
||||
sco_list_push_back(&sco_yielders, sco_cur);
|
||||
sco_nyielders += 2;
|
||||
sco_switch(false, false);
|
||||
// Reschedule the coroutine that started this one immediately after
|
||||
// all running coroutines, but before any yielding coroutines, and
|
||||
// continue running the started coroutine.
|
||||
sco_list_push_back(&sco_runners, sco_cur);
|
||||
sco_nrunners++;
|
||||
}
|
||||
sco_cur = co;
|
||||
if (sco_user_entry) {
|
||||
@@ -2622,6 +2635,12 @@ void *stack_addr(struct stack *stack) {
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef WORKER_STATIC
|
||||
#define WORKER_API static
|
||||
#else
|
||||
#define WORKER_API
|
||||
#endif
|
||||
|
||||
#define WORKER_DEF_TIMEOUT INT64_C(1000000000) // one second
|
||||
#define WORKER_DEF_MAX_THREADS 2
|
||||
#define WORKER_DEF_MAX_THREAD_ENTRIES 32
|
||||
@@ -2656,6 +2675,7 @@ struct worker {
|
||||
void (*free)(void*);
|
||||
};
|
||||
|
||||
WORKER_API
|
||||
void worker_free(struct worker *worker) {
|
||||
if (worker) {
|
||||
if (worker->threads) {
|
||||
@@ -2680,6 +2700,7 @@ void worker_free(struct worker *worker) {
|
||||
}
|
||||
}
|
||||
|
||||
WORKER_API
|
||||
struct worker *worker_new(struct worker_opts *opts) {
|
||||
// Load options
|
||||
int nthreads = opts ? opts->max_threads : 0;
|
||||
@@ -2774,6 +2795,7 @@ static void *worker_entry(void *arg) {
|
||||
/// @param udata any user data
|
||||
/// @return true for success or false if no worker is available.
|
||||
/// @return false for invalid arguments. Worker and work must no be null.
|
||||
WORKER_API
|
||||
bool worker_submit(struct worker *worker, int64_t pin, void(*work)(void *udata),
|
||||
void *udata)
|
||||
{
|
||||
@@ -2856,7 +2878,7 @@ bool worker_submit(struct worker *worker, int64_t pin, void(*work)(void *udata),
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#define NECO_POLL_EPOLL
|
||||
#elif defined(__EMSCRIPTEN__) || defined(_WIN32)
|
||||
#elif defined(__EMSCRIPTEN__) || defined(_WIN32) || defined(__COSMOCC__)
|
||||
// #warning Webassembly has no polling
|
||||
#define NECO_POLL_DISABLED
|
||||
#else
|
||||
@@ -3235,7 +3257,7 @@ struct cleanup {
|
||||
void (*routine)(void *);
|
||||
void *arg;
|
||||
struct cleanup *next;
|
||||
} aligned16;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// colist - The standard queue type that is just a doubly linked list storing
|
||||
@@ -3247,7 +3269,7 @@ struct coroutine;
|
||||
struct colink {
|
||||
struct coroutine *prev;
|
||||
struct coroutine *next;
|
||||
} aligned16;
|
||||
};
|
||||
|
||||
struct colist {
|
||||
struct colink head;
|
||||
@@ -3669,10 +3691,15 @@ static struct coroutine *evexists(int fd, enum evkind kind) {
|
||||
static int is_main_thread(void) {
|
||||
return IsGUIThread(false);
|
||||
}
|
||||
#elif defined(__linux__) || defined(__EMSCRIPTEN__)
|
||||
#elif defined(__linux__)
|
||||
static int is_main_thread(void) {
|
||||
return getpid() == (pid_t)syscall(SYS_gettid);
|
||||
}
|
||||
#elif defined(__EMSCRIPTEN__) || defined(__COSMOCC__)
|
||||
int gettid(void);
|
||||
static int is_main_thread(void) {
|
||||
return getpid() == gettid();
|
||||
}
|
||||
#else
|
||||
int pthread_main_np(void);
|
||||
static int is_main_thread(void) {
|
||||
@@ -4351,7 +4378,6 @@ static int run(void(*coroutine)(int, void**), int nargs, va_list *args,
|
||||
colist_init(&rt->iolist);
|
||||
#endif
|
||||
|
||||
|
||||
// Start the main coroutine. Actually, it's just queued to run first.
|
||||
ret = start(coroutine, nargs, args, argv, 0, 0);
|
||||
if (ret != NECO_OK) {
|
||||
@@ -7055,13 +7081,13 @@ int neco_serve(const char *network, const char *address) {
|
||||
|
||||
struct neco_mutex {
|
||||
int64_t rtid; // runtime id
|
||||
bool locked; // mutex is locked (read or write)
|
||||
int rlocked; // read lock counter
|
||||
struct colist queue; // coroutine doubly linked list
|
||||
int rlocked; // read lock counter
|
||||
bool locked; // mutex is locked (read or write)
|
||||
};
|
||||
|
||||
|
||||
static_assert(sizeof(neco_mutex) >= sizeof(struct neco_mutex), "");
|
||||
static_assert(_Alignof(neco_mutex) == _Alignof(struct neco_mutex), "");
|
||||
|
||||
static int mutex_init(neco_mutex *mutex) {
|
||||
struct neco_mutex *mu = (void*)mutex;
|
||||
@@ -7312,12 +7338,13 @@ int neco_mutex_destroy(neco_mutex *mutex) {
|
||||
}
|
||||
|
||||
struct neco_waitgroup {
|
||||
int64_t rtid;
|
||||
int count;
|
||||
struct colist queue;
|
||||
int64_t rtid; // runtime id
|
||||
struct colist queue; // coroutine doubly linked list
|
||||
int count; // current wait count
|
||||
};
|
||||
|
||||
static_assert(sizeof(neco_waitgroup) >= sizeof(struct neco_waitgroup), "");
|
||||
static_assert(_Alignof(neco_waitgroup) == _Alignof(struct neco_waitgroup), "");
|
||||
|
||||
inline
|
||||
static int check_waitgroup(struct neco_waitgroup *wg) {
|
||||
@@ -7460,11 +7487,12 @@ int neco_waitgroup_destroy(neco_waitgroup *waitgroup) {
|
||||
}
|
||||
|
||||
struct neco_cond {
|
||||
int64_t rtid; // runtime id
|
||||
struct colist queue; // coroutine doubly linked list
|
||||
int64_t rtid; // runtime id
|
||||
struct colist queue; // coroutine doubly linked list
|
||||
};
|
||||
|
||||
static_assert(sizeof(neco_cond) >= sizeof(struct neco_cond), "");
|
||||
static_assert(_Alignof(neco_cond) == _Alignof(struct neco_cond), "");
|
||||
|
||||
static int cond_init0(struct neco_cond *cv) {
|
||||
memset(cv, 0, sizeof(struct neco_cond));
|
||||
@@ -8685,6 +8713,7 @@ static void iowork(void *udata) {
|
||||
#endif
|
||||
|
||||
static int workfn(int64_t pin, void(*work)(void *udata), void *udata) {
|
||||
(void)pin;
|
||||
struct coroutine *co = coself();
|
||||
if (!work) {
|
||||
return NECO_INVAL;
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// basic operations
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -97,7 +101,7 @@ int neco_gen_close(neco_gen *gen);
|
||||
/// @}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// synchonization mechanisms
|
||||
// synchronization mechanisms
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup Mutexes Mutexes
|
||||
@@ -106,7 +110,7 @@ int neco_gen_close(neco_gen *gen);
|
||||
/// to a variable or set of variables and helps to avoid data inconsistencies
|
||||
/// due to race conditions.
|
||||
/// @{
|
||||
typedef struct { char _[48]; } neco_mutex;
|
||||
typedef struct { int64_t _0; intptr_t _1[5]; } neco_mutex;
|
||||
|
||||
#define NECO_MUTEX_INITIALIZER { 0 }
|
||||
|
||||
@@ -128,8 +132,7 @@ int neco_mutex_tryrdlock(neco_mutex *mutex);
|
||||
/// At the same time, neco_waitgroup_wait() can be used to block until all
|
||||
/// coroutines are completed.
|
||||
/// @{
|
||||
typedef struct { char _[48]; } neco_waitgroup;
|
||||
|
||||
typedef struct { int64_t _0; intptr_t _1[5]; } neco_waitgroup;
|
||||
#define NECO_WAITGROUP_INITIALIZER { 0 }
|
||||
|
||||
int neco_waitgroup_init(neco_waitgroup *waitgroup);
|
||||
@@ -143,7 +146,7 @@ int neco_waitgroup_wait_dl(neco_waitgroup *waitgroup, int64_t deadline);
|
||||
/// A condition variable is a synchronization mechanism that allows coroutines
|
||||
/// to suspend execution until some condition is true.
|
||||
/// @{
|
||||
typedef struct { char _[48]; } neco_cond;
|
||||
typedef struct { int64_t _0; intptr_t _1[5]; } neco_cond;
|
||||
#define NECO_COND_INITIALIZER { 0 }
|
||||
|
||||
int neco_cond_init(neco_cond *cond);
|
||||
@@ -208,7 +211,7 @@ int neco_dial_dl(const char *network, const char *address, int64_t deadline);
|
||||
/// @}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cancellation
|
||||
// cancelation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup Cancelation Cancelation
|
||||
@@ -225,8 +228,9 @@ int neco_cancel_dl(int64_t id, int64_t deadline);
|
||||
int neco_setcanceltype(int type, int *oldtype);
|
||||
int neco_setcancelstate(int state, int *oldstate);
|
||||
|
||||
#define neco_cleanup_push(routine, arg) {__neco_c0(&(char[32]){0},routine,arg);
|
||||
#define neco_cleanup_pop(execute) __neco_c1(execute);}
|
||||
#define neco_cleanup_push(routine, arg) {char __neco_handler[32]={0};\
|
||||
__neco_c0(__neco_handler,routine,arg);
|
||||
#define neco_cleanup_pop(execute) __neco_c1(execute);}
|
||||
|
||||
/// @}
|
||||
|
||||
@@ -261,13 +265,12 @@ int neco_signal_unwatch(int signo);
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// background worker
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// @defgroup Worker Background worker
|
||||
/// Run arbritary code in a background worker thread
|
||||
/// Run arbitrary code in a background worker thread
|
||||
/// @{
|
||||
|
||||
int neco_work(int64_t pin, void(*work)(void *udata), void *udata);
|
||||
@@ -422,10 +425,10 @@ ssize_t neco_stream_buffered_write_size(neco_stream *stream);
|
||||
#include <stdlib.h>
|
||||
|
||||
#define neco_main \
|
||||
static inline __neco_main0(int argc, char *argv[]); \
|
||||
__neco_main(int argc, char *argv[]); \
|
||||
static void _neco_main(int argc, void *argv[]) { \
|
||||
(void)argc; \
|
||||
__neco_exit_prog(__neco_main0(*(int*)argv[0], *(char***)argv[1])); \
|
||||
__neco_exit_prog(__neco_main(*(int*)argv[0], *(char***)argv[1])); \
|
||||
} \
|
||||
int main(int argc, char *argv[]) { \
|
||||
neco_env_setpaniconerror(true); \
|
||||
@@ -434,7 +437,7 @@ int main(int argc, char *argv[]) { \
|
||||
fprintf(stderr, "neco_start: %s (code %d)\n", neco_strerror(ret), ret); \
|
||||
return -1; \
|
||||
}; \
|
||||
int static inline __neco_main0
|
||||
int __neco_main
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private functions, not to be call directly
|
||||
@@ -450,4 +453,8 @@ void __neco_exit_prog(int);
|
||||
#define EAI_SYSTEM 11
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NECO_H
|
||||
|
||||
+26
-13
@@ -6,6 +6,7 @@ set -e
|
||||
cd $(dirname "${BASH_SOURCE[0]}")
|
||||
|
||||
OK=0
|
||||
FAILS=
|
||||
finish() {
|
||||
rm -fr *.o
|
||||
rm -fr *.out
|
||||
@@ -16,7 +17,7 @@ finish() {
|
||||
rm -fr *.c.worker.js
|
||||
rm -fr *.c.wasm
|
||||
if [[ "$OK" != "1" ]]; then
|
||||
echo "FAIL"
|
||||
echo "FAIL [`echo "$FAILS" | xargs`]"
|
||||
fi
|
||||
}
|
||||
trap finish EXIT
|
||||
@@ -43,8 +44,10 @@ fi
|
||||
if [[ "$CC" == "" ]]; then
|
||||
CC=cc
|
||||
fi
|
||||
UCFLAGS=$CFLAGS
|
||||
CFLAGS=
|
||||
if [[ "$1" != "bench" ]]; then
|
||||
CFLAGS="-O0 -g3 -Wall -Wextra -fstrict-aliasing $CFLAGS"
|
||||
CFLAGS="-O0 -g2 -Wall -Wextra -fstrict-aliasing $CFLAGS"
|
||||
CCVERSHEAD="$($CC --version | head -n 1)"
|
||||
if [[ "$CCVERSHEAD" == "" ]]; then
|
||||
exit 1
|
||||
@@ -52,8 +55,10 @@ if [[ "$1" != "bench" ]]; then
|
||||
|
||||
if [[ "$CCVERSHEAD" == *"clang"* ]]; then
|
||||
CLANGVERS="$(echo "$CCVERSHEAD" | awk '{print $4}' | awk -F'[ .]+' '{print $1}')"
|
||||
INSTALLDIR="$($CC --version | grep InstalledDir)"
|
||||
INSTALLDIR="${INSTALLDIR#* }"
|
||||
fi
|
||||
|
||||
|
||||
if [[ "$CC" == *"zig"* ]]; then
|
||||
# echo Zig does not support asans
|
||||
NOSANS=1
|
||||
@@ -109,14 +114,15 @@ elif [[ "`uname`" == *"_NT-"* ]]; then
|
||||
fi
|
||||
|
||||
if [[ "$CC" == *"zig"* ]]; then
|
||||
# Without -O3, 'zig cc' has quirks issues on Mac OS.
|
||||
CFLAGS="$CFLAGS -O3"
|
||||
# Stack unwinding is not supported yet
|
||||
# https://github.com/ziglang/zig/issues/9046
|
||||
CFLAGS="$CFLAGS -DLLCO_NOUNWIND"
|
||||
# Without -O1, 'zig cc' has quirks issues on Mac OS.
|
||||
if [[ "`uname`" == "Darwin" ]]; then
|
||||
CFLAGS="$CFLAGS -O1"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
CFLAGS="$CFLAGS $UCFLAGS"
|
||||
|
||||
CC=${CC:-cc}
|
||||
echo "CC: $CC"
|
||||
@@ -205,6 +211,7 @@ else
|
||||
if [[ "$WITHCOV" == "1" ]]; then
|
||||
export LLVM_PROFILE_FILE="$f.profraw"
|
||||
fi
|
||||
set +e
|
||||
if [[ "$VALGRIND" == "1" ]]; then
|
||||
valgrind --leak-check=yes ./$f.test $@
|
||||
elif [[ "$CC" == "emcc" ]]; then
|
||||
@@ -212,24 +219,30 @@ else
|
||||
else
|
||||
./$f.test $@
|
||||
fi
|
||||
|
||||
if [[ "$?" != "0" ]]; then
|
||||
FAILS="$FAILS$(echo "$f" | cut -f 1 -d '.') "
|
||||
fi
|
||||
set -e
|
||||
done
|
||||
OK=1
|
||||
echo "OK"
|
||||
if [[ "$FAILS" == "" ]]; then
|
||||
OK=1
|
||||
echo "OK"
|
||||
fi
|
||||
|
||||
|
||||
if [[ "$COVREGIONS" == "" ]]; then
|
||||
COVREGIONS="false"
|
||||
fi
|
||||
|
||||
if [[ "$WITHCOV" == "1" ]]; then
|
||||
$LLVM_PROFDATA merge *.profraw -o test.profdata
|
||||
$LLVM_COV report *.test ../neco.c -ignore-filename-regex=.test. \
|
||||
$INSTALLDIR/$LLVM_PROFDATA merge *.profraw -o test.profdata
|
||||
$INSTALLDIR/$LLVM_COV report *.test ../neco.c -ignore-filename-regex=.test. \
|
||||
-j=4 \
|
||||
-show-functions=true \
|
||||
-instr-profile=test.profdata > /tmp/test.cov.sum.txt
|
||||
# echo coverage: $(cat /tmp/test.cov.sum.txt | grep TOTAL | awk '{ print $NF }')
|
||||
echo covered: "$(cat /tmp/test.cov.sum.txt | grep TOTAL | awk '{ print $7; }') (lines)"
|
||||
$LLVM_COV show *.test ../neco.c -ignore-filename-regex=.test. \
|
||||
$INSTALLDIR/$LLVM_COV show *.test ../neco.c -ignore-filename-regex=.test. \
|
||||
-j=4 \
|
||||
-show-regions=true \
|
||||
-show-expansions=$COVREGIONS \
|
||||
|
||||
+3
-3
@@ -96,14 +96,14 @@ void co_sched1(int argc, void *argv[]) {
|
||||
int *i = argv[1];
|
||||
a[(*i)++] = 'B';
|
||||
assert(neco_yield() == NECO_OK);
|
||||
a[(*i)++] = 'D';
|
||||
a[(*i)++] = 'F';
|
||||
}
|
||||
|
||||
void co_sched2(int argc, void *argv[]) {
|
||||
assert(argc == 2);
|
||||
char *a = argv[0];
|
||||
int *i = argv[1];
|
||||
a[(*i)++] = 'E';
|
||||
a[(*i)++] = 'D';
|
||||
assert(neco_yield() == NECO_OK);
|
||||
a[(*i)++] = 'G';
|
||||
}
|
||||
@@ -116,7 +116,7 @@ void co_sched(int argc, void *argv[]) {
|
||||
assert(neco_start(co_sched1, 2, a, i) == NECO_OK);
|
||||
a[(*i)++] = 'C';
|
||||
assert(neco_start(co_sched2, 2, a, i) == NECO_OK);
|
||||
a[(*i)++] = 'F';
|
||||
a[(*i)++] = 'E';
|
||||
assert(neco_yield() == NECO_OK);
|
||||
a[(*i)++] = 'H';
|
||||
}
|
||||
|
||||
@@ -343,30 +343,6 @@ void test_sync_cond_deadline(void) {
|
||||
expect(neco_start(co_sync_cond_deadline, 0), NECO_OK);
|
||||
}
|
||||
|
||||
void co_sync_mutex_rw_order_child2(int argc, void *argv[]) {
|
||||
assert(argc == 2);
|
||||
neco_mutex *mu = argv[0];
|
||||
struct order *order = argv[1];
|
||||
order_add(order, 17);
|
||||
expect(neco_mutex_rdlock(mu), NECO_OK);
|
||||
order_add(order, 23);
|
||||
expect(neco_mutex_unlock(mu), NECO_OK);
|
||||
order_add(order, 26);
|
||||
}
|
||||
|
||||
void co_sync_mutex_rw_order_child3(int argc, void *argv[]) {
|
||||
assert(argc == 2);
|
||||
neco_mutex *mu = argv[0];
|
||||
struct order *order = argv[1];
|
||||
order_add(order, 19);
|
||||
expect(neco_mutex_trylock(mu), NECO_BUSY);
|
||||
order_add(order, 20);
|
||||
expect(neco_mutex_rdlock(mu), NECO_OK);
|
||||
order_add(order, 24);
|
||||
expect(neco_mutex_unlock(mu), NECO_OK);
|
||||
order_add(order, 27);
|
||||
}
|
||||
|
||||
void co_sync_mutex_rw_order_child(int argc, void *argv[]) {
|
||||
assert(argc == 2);
|
||||
neco_mutex *mu = argv[0];
|
||||
@@ -382,12 +358,6 @@ void co_sync_mutex_rw_order_child(int argc, void *argv[]) {
|
||||
order_add(order, 13);
|
||||
expect(neco_yield(), NECO_OK);
|
||||
order_add(order, 14);
|
||||
expect(neco_start(co_sync_mutex_rw_order_child2, 2, mu, order), NECO_OK);
|
||||
order_add(order, 18);
|
||||
expect(neco_start(co_sync_mutex_rw_order_child3, 2, mu, order), NECO_OK);
|
||||
order_add(order, 21);
|
||||
expect(neco_mutex_unlock(mu), NECO_OK);
|
||||
order_add(order, 28);
|
||||
}
|
||||
|
||||
void co_sync_mutex_rw_order(int argc, void *argv[]) {
|
||||
@@ -414,15 +384,6 @@ void co_sync_mutex_rw_order(int argc, void *argv[]) {
|
||||
order_add(&order, 12);
|
||||
expect(neco_mutex_unlock(mu), NECO_OK);
|
||||
order_add(&order, 15);
|
||||
expect(neco_mutex_tryrdlock(mu), NECO_BUSY);
|
||||
order_add(&order, 16);
|
||||
expect(neco_mutex_rdlock(mu), NECO_OK);
|
||||
order_add(&order, 22);
|
||||
expect(neco_mutex_unlock(mu), NECO_OK);
|
||||
order_add(&order, 25);
|
||||
expect(neco_yield(), NECO_OK);
|
||||
order_add(&order, 29);
|
||||
expect(neco_mutex_destroy(mu), NECO_OK);
|
||||
order_check(&order);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ void co_work_runner(int argc, void *argv[]) {
|
||||
|
||||
void co_work(int argc, void *argv[]) {
|
||||
(void)argc; (void)argv;
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
expect(neco_start(co_work_runner, 1, &i), NECO_OK);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user