Implement poll() on top of select()
[akaros.git] / user / pthread / pthread.c
index 9c69da8..9a6691e 100644 (file)
@@ -16,6 +16,7 @@
 #include <parlib/event.h>
 #include <parlib/ucq.h>
 #include <parlib/signal.h>
+#include <parlib/arch/trap.h>
 
 struct pthread_queue ready_queue = TAILQ_HEAD_INITIALIZER(ready_queue);
 struct pthread_queue active_queue = TAILQ_HEAD_INITIALIZER(active_queue);
@@ -23,7 +24,6 @@ struct mcs_pdr_lock queue_lock;
 int threads_ready = 0;
 int threads_active = 0;
 atomic_t threads_total;
-bool can_adjust_vcores = TRUE;
 bool need_tls = TRUE;
 
 /* Array of per-vcore structs to manage waiting on syscalls and handling
@@ -41,8 +41,8 @@ static void pth_thread_runnable(struct uthread *uthread);
 static void pth_thread_paused(struct uthread *uthread);
 static void pth_thread_blockon_sysc(struct uthread *uthread, void *sysc);
 static void pth_thread_has_blocked(struct uthread *uthread, int flags);
-static void pth_thread_refl_fault(struct uthread *uthread, unsigned int trap_nr,
-                                  unsigned int err, unsigned long aux);
+static void pth_thread_refl_fault(struct uthread *uth,
+                                  struct user_context *ctx);
 
 /* Event Handlers */
 static void pth_handle_syscall(struct event_msg *ev_msg, unsigned int ev_type,
@@ -106,11 +106,8 @@ static void __attribute__((noreturn)) pth_sched_entry(void)
                /* no new thread, try to yield */
                printd("[P] No threads, vcore %d is yielding\n", vcore_id());
                /* TODO: you can imagine having something smarter here, like spin for a
-                * bit before yielding (or not at all if you want to be greedy). */
-               if (can_adjust_vcores)
-                       vcore_yield(FALSE);
-               if (!parlib_wants_to_be_mcp)
-                       sys_yield(FALSE);
+                * bit before yielding. */
+               vcore_yield(FALSE);
        } while (1);
        /* Prep the pthread to run any pending posix signal handlers registered
      * via pthread_kill once it is restored. */
@@ -159,8 +156,7 @@ static void pth_thread_runnable(struct uthread *uthread)
        mcs_pdr_unlock(&queue_lock);
        /* Smarter schedulers should look at the num_vcores() and how much work is
         * going on to make a decision about how many vcores to request. */
-       if (can_adjust_vcores)
-               vcore_request(threads_ready);
+       vcore_request_more(threads_ready);
 }
 
 /* For some reason not under its control, the uthread stopped running (compared
@@ -287,67 +283,57 @@ static void handle_page_fault(struct uthread *uthread, unsigned int err,
        if (!(err & PF_VMR_BACKED)) {
                __signal_and_restart(uthread, SIGSEGV, SEGV_MAPERR, (void*)aux);
        } else {
-               /* stitching for the event handler.  sysc -> uth, uth -> sysc */
-               uthread->local_sysc.u_data = uthread;
-               uthread->sysc = &uthread->local_sysc;
-               pthread->state = PTH_BLK_SYSC;
-               /* one downside is that we'll never check the return val of the syscall.  if
-                * we errored out, we wouldn't know til we PF'd again, and inspected the old
-                * retval/err and other sysc fields (make sure the PF is on the same addr,
-                * etc).  could run into this issue on truncated files too. */
                syscall_async(&uthread->local_sysc, SYS_populate_va, aux, 1);
-               if (!register_evq(&uthread->local_sysc, sysc_mgmt[vcore_id()].ev_q)) {
-                       /* Lost the race with the call being done.  The kernel won't send the
-                        * event.  Just restart him. */
-                       restart_thread(&uthread->local_sysc);
-               }
+               __block_uthread_on_async_sysc(uthread);
        }
 }
 
-static void pth_thread_refl_fault(struct uthread *uthread, unsigned int trap_nr,
-                                  unsigned int err, unsigned long aux)
+static void pth_thread_refl_hw_fault(struct uthread *uthread,
+                                     unsigned int trap_nr,
+                                     unsigned int err, unsigned long aux)
 {
        struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
 
        __pthread_generic_yield(pthread);
        pthread->state = PTH_BLK_SYSC;
 
-       /* TODO: RISCV/x86 issue! (0 is divby0, 14 is PF, etc) */
-#if defined(__i386__) || defined(__x86_64__) 
-       switch(trap_nr) {
-               case 0:
-                       handle_div_by_zero(uthread, err, aux);
-                       break;
-               case 13:
-                       handle_gp_fault(uthread, err, aux);
-                       break;
-               case 14:
-                       handle_page_fault(uthread, err, aux);
-                       break;
-               default:
-                       printf("Pthread has unhandled fault: %d, err: %d, aux: %p\n",
-                              trap_nr, err, aux);
-                       /* Note that uthread.c already copied out our ctx into the uth
-                        * struct */
-                       print_user_context(&uthread->u_ctx);
-                       printf("Turn on printx to spew unhandled, malignant trap info\n");
-                       exit(-1);
+       switch (trap_nr) {
+       case HW_TRAP_DIV_ZERO:
+               handle_div_by_zero(uthread, err, aux);
+               break;
+       case HW_TRAP_GP_FAULT:
+               handle_gp_fault(uthread, err, aux);
+               break;
+       case HW_TRAP_PAGE_FAULT:
+               handle_page_fault(uthread, err, aux);
+               break;
+       default:
+               printf("Pthread has unhandled fault: %d, err: %d, aux: %p\n",
+                      trap_nr, err, aux);
+               /* Note that uthread.c already copied out our ctx into the uth
+                * struct */
+               print_user_context(&uthread->u_ctx);
+               printf("Turn on printx to spew unhandled, malignant trap info\n");
+               exit(-1);
        }
-#else
-       #error "Handling hardware faults is currently only supported on x86"
-#endif
 }
 
-/* Akaros pthread extensions / hacks */
-
-/* Tells the pthread 2LS to not change the number of vcores.  This means it will
- * neither request vcores nor yield vcores.  Only used for testing. */
-void pthread_can_vcore_request(bool can)
+static void pth_thread_refl_fault(struct uthread *uth,
+                                  struct user_context *ctx)
 {
-       /* checked when we would request or yield */
-       can_adjust_vcores = can;
+       switch (ctx->type) {
+       case ROS_HW_CTX:
+               pth_thread_refl_hw_fault(uth, __arch_refl_get_nr(ctx),
+                                        __arch_refl_get_err(ctx),
+                                        __arch_refl_get_aux(ctx));
+               break;
+       default:
+               assert(0);
+       }
 }
 
+/* Akaros pthread extensions / hacks */
+
 void pthread_need_tls(bool need)
 {
        need_tls = need;
@@ -542,13 +528,6 @@ void pthread_mcp_init()
        /* Prevent this from happening more than once. */
        init_once_racy(return);
 
-       if (!parlib_wants_to_be_mcp) {
-               /* sign to whether or not we ask for more vcores.  actually, if we're
-                * an SCP, the current kernel will ignore our requests, but best to not
-                * rely on that. */
-               can_adjust_vcores = FALSE;
-               return;
-       }
        uthread_mcp_init();
        /* From here forward we are an MCP running on vcore 0. Could consider doing
         * other pthread specific initialization based on knowing we are an mcp
@@ -924,8 +903,7 @@ static void wake_slist(struct pthread_list *to_wake)
        }
        threads_ready += nr_woken;
        mcs_pdr_unlock(&queue_lock);
-       if (can_adjust_vcores)
-               vcore_request(threads_ready);
+       vcore_request_more(threads_ready);
 }
 
 int pthread_cond_broadcast(pthread_cond_t *c)