diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c index 5809c1ea95e08a3249df733a6c6753c8a4548fe3..b8eddd9eeb22aa85904e7f8eb888f63dd01b29af 100644 --- a/gtests/net/packetdrill/run_system_call.c +++ b/gtests/net/packetdrill/run_system_call.c @@ -39,6 +39,14 @@ #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> +#if defined(__FreeBSD__) +#include <kvm.h> +#include <sys/sysctl.h> +#include <sys/user.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <libprocstat.h> +#endif #include <sys/socket.h> #include <sys/syscall.h> #include <sys/types.h> @@ -100,16 +108,11 @@ static int check_sctp_sndrcvinfo(struct sctp_sndrcvinfo_expr *expr, char** error); #endif +#if defined(linux) /* Provide a wrapper for the Linux gettid() system call (glibc does not). */ static pid_t gettid(void) { -#ifdef linux return syscall(__NR_gettid); -#endif -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) - /* TODO(ncardwell): Implement me. XXX */ - return 0; -#endif /* defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)*/ } /* Read a whole file into the given buffer of the given length. */ @@ -157,6 +160,50 @@ static bool is_thread_sleeping(pid_t process_id, pid_t thread_id) return is_sleeping; } +#elif defined(__FreeBSD__) +static bool is_thread_sleeping(pid_t process_id, int thread_id) +{ + struct procstat *procstat; + struct kinfo_proc *kinfo_proc; + unsigned int i, count; + bool is_sleeping; + + procstat = procstat_open_sysctl(); + if (procstat == NULL) { + die("procstat_open_sysctl() failed\n"); + } + /* Get the information for all threads belonging to the given process. + * The number of entries (one for each thread) is returned in count. + */ + kinfo_proc = procstat_getprocs(procstat, + KERN_PROC_PID | KERN_PROC_INC_THREAD, + process_id, &count); + if (kinfo_proc == NULL) { + die("procstat_getprocs() failed\n"); + } + /* Do a linear search to the entry for the requested thread. + * Since we have only two threads, that's OK performance-wise. + */ + for (i = 0; i < count; i++) { + if (kinfo_proc[i].ki_tid == thread_id) + break; + } + /* Die, if we can't find the entry for the requested thread. */ + if (i == count) + die("unable to get state of thread %d\n", thread_id); + is_sleeping = (kinfo_proc[i].ki_stat == SSLEEP); + /* Cleanup the allocated data structures. */ + procstat_freeprocs(procstat, kinfo_proc); + procstat_close(procstat); + return is_sleeping; +} +#else +static bool is_thread_sleeping(pid_t process_id, int thread_id) +{ + die("is_thread_sleeping not implemented on this platform\n"); + return true; +} +#endif /* Returns number of expressions in the list. */ static int expression_list_length(struct expression_list *list) @@ -6123,11 +6170,19 @@ static void enqueue_system_call( /* Wait for the syscall thread to block or finish the call. */ while (!done) { +#if defined(linux) + pid_t thread_id; +#elif defined(__FreeBSD__) + int thread_id; +#else + int thread_id; /* FIXME */ +#endif + /* Unlock and yield so the system call thread can make * the system call in a timely fashion. */ DEBUGP("main thread: unlocking and yielding\n"); - pid_t thread_id = state->syscalls->thread_id; + thread_id = state->syscalls->thread_id; run_unlock(state); if (yield() != 0) die_perror("yield"); @@ -6187,9 +6242,15 @@ static void *system_call_thread(void *arg) DEBUGP("syscall thread: starting and locking\n"); run_lock(state); +#if defined(linux) state->syscalls->thread_id = gettid(); if (state->syscalls->thread_id < 0) die_perror("gettid"); +#elif defined(__FreeBSD__) + state->syscalls->thread_id = pthread_getthreadid_np(); +#else + state->syscalls->thread_id = 0 /* FIXME */ +#endif while (!done) { DEBUGP("syscall thread: in state %d\n", diff --git a/gtests/net/packetdrill/run_system_call.h b/gtests/net/packetdrill/run_system_call.h index 570b7fa7e496bd728015b5b56672411250156234..7dbd0887748c3f0dec0114cc8ddfc8f0333a620d 100644 --- a/gtests/net/packetdrill/run_system_call.h +++ b/gtests/net/packetdrill/run_system_call.h @@ -51,7 +51,13 @@ struct syscalls { /* Handles for the syscall thread, for blocking system calls. */ pthread_t thread; /* pthread thread handle */ +#if defined(linux) pid_t thread_id; /* kernel thread ID */ +#elif defined(__FreeBSD__) + int thread_id; +#else + int thread_id; /* FIXME */ +#endif /* The main thread waits on this condition variable. The * system call thread signals this when it has finished