示例#1
0
文件: pthread.c 项目: kstraube/hysim
/* This will be called from vcore context, after the current thread has yielded
 * and is trying to block on sysc.  Need to put it somewhere were we can wake it
 * up when the sysc is done.  For now, we'll have the kernel send us an event
 * when the syscall is done. */
void pth_blockon_sysc(struct syscall *sysc)
{
	int old_flags;
	bool need_to_restart = FALSE;
	uint32_t vcoreid = vcore_id();

	assert(current_uthread->state == UT_BLOCKED);
	/* rip from the active queue */
	struct mcs_lock_qnode local_qn = {0};
	struct pthread_tcb *pthread = (struct pthread_tcb*)current_uthread;
	mcs_lock_notifsafe(&queue_lock, &local_qn);
	threads_active--;
	TAILQ_REMOVE(&active_queue, pthread, next);
	mcs_unlock_notifsafe(&queue_lock, &local_qn);

	/* Set things up so we can wake this thread up later */
	sysc->u_data = current_uthread;
	/* Put the uthread on the pending list.  Note the ordering.  We must be on
	 * the list before we register the ev_q.  All sysc's must be tracked before
	 * we tell the kernel to signal us. */
	TAILQ_INSERT_TAIL(&sysc_mgmt[vcoreid].pending_syscs, pthread, next);
	/* Safety: later we'll make sure we restart on the core we slept on */
	pthread->vcoreid = vcoreid;
	/* Register our vcore's syscall ev_q to hear about this syscall. */
	if (!register_evq(sysc, &sysc_mgmt[vcoreid].ev_q)) {
		/* Lost the race with the call being done.  The kernel won't send the
		 * event.  Just restart him. */
		restart_thread(sysc);
	}
	/* GIANT WARNING: do not touch the thread after this point. */
}
示例#2
0
文件: pthread.c 项目: kstraube/hysim
/* This handler is usually run in vcore context, though I can imagine it being
 * called by a uthread in some other threading library. */
static void pth_handle_syscall(struct event_msg *ev_msg, unsigned int ev_type,
                               bool overflow)
{
	struct syscall *sysc;
	assert(in_vcore_context());
	if (overflow) {
		handle_sysc_overflow();
	}
	if (!ev_msg) {
		/* Probably a bug somewhere if we had no ev_msg and no overflow */
		if (!overflow)
			printf("[pthread] crap, no ev_msg!!\n");
		return;
	}
	sysc = ev_msg->ev_arg3;
	assert(sysc);
	restart_thread(sysc);
}
示例#3
0
文件: pthread.c 项目: windyuuy/akaros
/* This handler is usually run in vcore context, though I can imagine it being
 * called by a uthread in some other threading library. */
static void pth_handle_syscall(struct event_msg *ev_msg, unsigned int ev_type,
                               void *data)
{
	struct syscall *sysc;
	assert(in_vcore_context());
	/* if we just got a bit (not a msg), it should be because the process is
	 * still an SCP and hasn't started using the MCP ev_q yet (using the simple
	 * ev_q and glibc's blockon) or because the bit is still set from an old
	 * ev_q (blocking syscalls from before we could enter vcore ctx).  Either
	 * way, just return.  Note that if you screwed up the pth ev_q and made it
	 * NO_MSG, you'll never notice (we used to assert(ev_msg)). */
	if (!ev_msg)
		return;
	/* It's a bug if we don't have a msg (we're handling a syscall bit-event) */
	assert(ev_msg);
	/* Get the sysc from the message and just restart it */
	sysc = ev_msg->ev_arg3;
	assert(sysc);
	restart_thread(sysc);
}
示例#4
0
文件: pthread.c 项目: windyuuy/akaros
/* This will be called from vcore context, after the current thread has yielded
 * and is trying to block on sysc.  Need to put it somewhere were we can wake it
 * up when the sysc is done.  For now, we'll have the kernel send us an event
 * when the syscall is done. */
static void pth_thread_blockon_sysc(struct uthread *uthread, void *syscall)
{
	struct syscall *sysc = (struct syscall*)syscall;
	int old_flags;
	uint32_t vcoreid = vcore_id();
	/* rip from the active queue */
	struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
	pthread->state = PTH_BLK_SYSC;
	mcs_pdr_lock(&queue_lock);
	threads_active--;
	TAILQ_REMOVE(&active_queue, pthread, tq_next);
	mcs_pdr_unlock(&queue_lock);
	/* Set things up so we can wake this thread up later */
	sysc->u_data = uthread;
	/* Register our vcore's syscall ev_q to hear about this syscall. */
	if (!register_evq(sysc, sysc_mgmt[vcoreid].ev_q)) {
		/* Lost the race with the call being done.  The kernel won't send the
		 * event.  Just restart him. */
		restart_thread(sysc);
	}
	/* GIANT WARNING: do not touch the thread after this point. */
}
示例#5
0
文件: pthread.c 项目: windyuuy/akaros
static void handle_page_fault(struct uthread *uthread, unsigned int err,
                              unsigned long aux)
{
	struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
	if (!(err & PF_VMR_BACKED)) {
		__pthread_signal_and_restart(pthread, 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);
		}
	}
}
示例#6
0
void cancel_test(void)
{
  pthread_t waiter;
  void *result;
  int status;

  /* Test 1: Normal Cancel *********************************************/
  /* Start the waiter thread  */

  printf("cancel_test: Test 1: Normal Cancelation\n");
  printf("cancel_test: Starting thread\n");
  start_thread(&waiter, 1);

  /* Then cancel it.  It should be in the pthread_cond_wait now */

  printf("cancel_test: Canceling thread\n");
  status = pthread_cancel(waiter);
  if (status != 0)
    {
      printf("cancel_test: ERROR pthread_cancel failed, status=%d\n", status);
    }

  /* Then join to the thread to pick up the result (if we don't do
   * we will have a memory leak!)
   */

  printf("cancel_test: Joining\n");
  status = pthread_join(waiter, &result);
  if (status != 0)
    {
      printf("cancel_test: ERROR pthread_join failed, status=%d\n", status);
    }
  else
    {
      printf("cancel_test: waiter exited with result=%p\n", result);
      if (result != PTHREAD_CANCELED)
        {
          printf("cancel_test: ERROR expected result=%p\n", PTHREAD_CANCELED);
        }
      else
        {
          printf("cancel_test: PASS thread terminated with PTHREAD_CANCELED\n");
        }
    }

  /* Test 2: Cancel Detached Thread ************************************/

  printf("cancel_test: Test 2: Cancelation of detached thread\n");
  printf("cancel_test: Re-starting thread\n");
  restart_thread(&waiter, 1);

  /* Detach the thread */

  status = pthread_detach(waiter);
  if (status != 0)
    {
      printf("cancel_test: ERROR pthread_detach, status=%d\n", status);
    }

  /* Then cancel it.  It should be in the pthread_cond_wait now */

  printf("cancel_test: Canceling thread\n");
  status = pthread_cancel(waiter);
  if (status != 0)
    {
      printf("cancel_test: ERROR pthread_cancel failed, status=%d\n", status);
    }

  /* Join should now fail */

  printf("cancel_test: Joining\n");
  status = pthread_join(waiter, &result);
  if (status == 0)
    {
      printf("cancel_test: ERROR pthread_join succeeded\n");
    }
  else if (status != ESRCH)
    {
      printf("cancel_test: ERROR pthread_join failed but with wrong status=%d\n", status);
    }
  else
    {
      printf("cancel_test: PASS pthread_join failed with status=ESRCH\n");
    }

  /* Test 3: Non-cancelable threads ************************************/

  printf("cancel_test: Test 3: Non-cancelable threads\n");
  printf("cancel_test: Re-starting thread (non-cancelable)\n");
  restart_thread(&waiter, 0);

  /* Then cancel it.  It should be in the pthread_cond_wait now.  The
   * behavior here is non-standard:  when the thread is at a cancelation
   * point, it should be cancelable, even when cancelation is disable.
   *
   * The cancelation should succeed, because the cancelation is pending.
   */

  printf("cancel_test: Canceling thread\n");
  status = pthread_cancel(waiter);
  if (status != 0)
    {
      printf("cancel_test: ERROR pthread_cancel failed, status=%d\n", status);
    }

  /* Signal the thread.  It should wake up and restore the cancelable state.
   * When the cancelable state is re-enabled, the thread should be canceled.
   */

  status = pthread_mutex_lock(&mutex);
  if (status != 0)
    {
      printf("cancel_test: ERROR pthread_mutex_lock failed, status=%d\n", status);
    }

  status = pthread_cond_signal(&cond);
  if (status != 0)
    {
      printf("cancel_test: ERROR pthread_cond_signal failed, status=%d\n", status);
    }

  status = pthread_mutex_unlock(&mutex);
  if (status != 0)
    {
      printf("cancel_test: ERROR pthread_mutex_unlock failed, status=%d\n", status);
    }

  /* Then join to the thread to pick up the result (if we don't do
   * we will have a memory leak!)
   */

  printf("cancel_test: Joining\n");
  status = pthread_join(waiter, &result);
  if (status != 0)
    {
      printf("cancel_test: ERROR pthread_join failed, status=%d\n", status);
    }
  else
    {
      printf("cancel_test: waiter exited with result=%p\n", result);
      if (result != PTHREAD_CANCELED)
        {
          printf("cancel_test: ERROR expected result=%p\n", PTHREAD_CANCELED);
        }
      else
        {
          printf("cancel_test: PASS thread terminated with PTHREAD_CANCELED\n");
        }
    }

}