⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 thread-impl.c

📁 java virtual machince kaffe
💻 C
📖 第 1 页 / 共 4 页
字号:
	 */	if (creation_succeeded != 0) {	  switch(creation_succeeded) {	  case EAGAIN: 	    DBG( JTHREAD, dprintf( "too many threads (%d)\n", nSysThreads));	    break;	  case EINVAL:	    DBG( JTHREAD, dprintf( "invalid value for nt.attr\n"));	    break;	  case EPERM:	    DBG( JTHREAD, dprintf( "no permission to set scheduling\n"));	    break;	  default:	    break;	  }	  repsem_destroy( &nt->sem);	  KGC_rmRef(threadCollector, nt);	  nt->active = 0;	  activeThreads = nt->next;	  unprotectThreadList(cur);	  return NULL;	}	/* wait until the thread specific data has been set, and the new thread	 * is in a suspendable state */	repsem_wait( &nt->sem);	/* The key is installed. We can now let the signals coming. */	unprotectThreadList(cur);  }  return (nt);}/*********************************************************************** * thread exit & cleanup *//* * Native thread cleanup. This is just called in case a native thread * is not cached */staticvoid tDispose ( jthread_t nt ){  /* We must lock the GC to prevent any garbage collection in this   * function.   */  jthread_lockGC();  /* Remove the static reference so the thread context may be freed. */  KGC_rmRef(threadCollector, nt);  KaffeVM_unlinkNativeAndJavaThread();  pthread_detach( nt->tid);  pthread_mutex_destroy (&nt->suspendLock);  repsem_destroy( &nt->sem);  /* The context is not freed explictly as it may cause troubles   * with the locking system which is invoked by the GC in that case.   * The thread context will be automatically freed by the GC in its    * thread context.   */  jthread_unlockGC();}/** * Function to be called (by threads.c firstStartThread) when the thread leaves * the user thread function. If the calling thread is the main thread then it * suspend the thread until all other threads has exited. */voidjthread_exit ( void ){  jthread_t	cur = jthread_current();  jthread_t	t;  /*   * We are leaving the thread user func, which means we are not   * subject to GC, anymore (has to be marked here because the first thread   * never goes through tRun)   */  cur->active = 0;  DBG( JTHREAD, TMSG_SHORT( "exit ", cur));  DBG( JTHREAD, dprintf("exit with %d non daemons (%x)\n", nonDaemons, cur->daemon));  if ( !cur->daemon ) {	/* the last non daemon should shut down the process */	protectThreadList(cur);	if ( --nonDaemons == 0 ) {	  DBG( JTHREAD, dprintf("exit on last nonDaemon\n"));	  if (runOnExit != NULL) {	    unprotectThreadList(cur);	    runOnExit();	    protectThreadList(cur);	  }	  /*	   * be a nice citizen, try to cancel all other threads before we	   * bail out, to give them a chance to run their cleanup handlers	   */	  for ( t=cache; t != NULL; t = t->next ){		t->status = THREAD_KILL;		repsem_post(&t->sem);	  }	  t = activeThreads;	  while (t != NULL) {		/* We must not kill the current thread and the main thread		 */		if ( t != cur && t != firstThread && t->active) {		  /* Mark the thread as to be killed. */		  t->status = THREAD_KILL;		  /* Send an interrupt event to the remote thread to wake up.		   * This may not work in any cases. However that way we prevent a		   * predictable deadlock on some threads implementation.		   */		  jthread_interrupt(t);		  unprotectThreadList(cur);		  pthread_join(t->tid, NULL);		  protectThreadList(cur);		  t = activeThreads;		} else		  t = t->next;	  }#if defined(KAFFE_VMDEBUG)	  if ( deadlockWatchdog ){		pthread_cancel( deadlockWatchdog);	  }#endif	  if ( (cur != firstThread) && (firstThread->active == 0) ) {		/* if the firstThread has already been frozen,		 * it's not in the cache list. We must wake it up because		 * this thread is the last one alive and it is exiting. */		repsem_post (&firstThread->sem);	  }	  /* This is not the main thread so we may kill it. */	  if (cur != firstThread)	  {	    unprotectThreadList(cur);	    pthread_exit( NULL);	    /* we shouldn't get here, this is a last safeguard */	    KAFFEVM_EXIT(0);	  }	}	unprotectThreadList(cur);  }  /*   * We don't cache this one, but we have to remove it from the active list. Note   * that the firstThread always has to be the last entry in the activeThreads list   * (we just add new entries at the head)   */  protectThreadList(cur);  if ( cur == firstThread && nonDaemons != 0) {	/* if we would be the head, we would have been the last, too (and already exited) */	assert( cur != activeThreads);	for ( t=activeThreads; (t != NULL) && (t->next != cur); t=t->next );	assert( t != NULL);	t->next = NULL;	unprotectThreadList(cur);	/* Put the main thread in a frozen state waiting for the other	 * real threads to terminate. The main thread gets the control back	 * after that.	 */	while (repsem_wait( &cur->sem) != 0);  }  else if (cur != firstThread) {	/* flag that we soon will get a new cache entry (would be annoying to	 * create a new thread in the meantime) */	pendingExits++;	unprotectThreadList(cur);  }  else unprotectThreadList(cur);}/* * Thread is being finalized - free any held resource. */voidjthread_destroy (jthread_t cur){  DBG( JTHREAD, TMSG_SHORT( "finalize ", cur));}void jthread_sleep (jlong timeout) {#ifdef __INTERIX	unsigned int seconds = timeout / 1000;	useconds_t   microseconds = (timeout % 1000) * 1000;	if (0 == sleep(seconds))		usleep(microseconds);#else	struct timespec ts;	ts.tv_sec  = timeout / 1000;	ts.tv_nsec = (timeout % 1000) * 1000000;	nanosleep (&ts, NULL);#endif}/*********************************************************************** * scheduling and query *//* * Change the scheduler priority of a running thread. Since we aren't * called directly, we can assume that 'prio' is within [MIN_PRIORITY..MAX_PRIORITY] */#if defined(SCHEDUL_POLICY)voidjthread_setpriority (jthread_t cur, jint prio){  struct sched_param   sp;  if ( cur ) {	sp.sched_priority = priorities[prio];	DBG( JTHREAD, dprintf("set priority: %p [tid: %4ld, java: %p) to %d (%d)\n",			      cur, cur->tid, cur->data.jlThread, prio, priorities[prio]))	pthread_setschedparam( cur->tid, SCHEDULE_POLICY, &sp);  }}#elsevoidjthread_setpriority (jthread_t cur UNUSED, jint prio UNUSED){}#endif/** * yield. * */void jthread_yield (void){#if defined(HAVE_PTHREAD_YIELD)  pthread_yield();#elif defined(HAVE_SCHED_YIELD)  sched_yield();#endif}/****************************************************************************** * the GC lock */static pthread_mutex_t GClock = PTHREAD_MUTEX_INITIALIZER;void jthread_lockGC(void){  pthread_mutex_lock(&GClock);}void jthread_unlockGC(void){  pthread_mutex_unlock(&GClock);}/******************************************************************************* * the suspend/resume mechanism *//** * This function make the enters in deep suspend mode. It is generally called * suspend_signal_handler() and the locking mechanism when a thread has called * jthread_suspendall(). It temporarily changes the state of the signal mask * for the current thread. * * @param releaseMutex If true, the function is requested to change the signal * mask and to release the suspendLock mutex only after this. In that case we * keep in sync with jthread_suspendall() */void KaffePThread_WaitForResume(int releaseMutex, unsigned int state){  volatile jthread_t cur = jthread_current();  int s;  sigset_t oldset;  if (releaseMutex)    {      pthread_sigmask(SIG_BLOCK, &suspendSet, &oldset);      pthread_mutex_unlock(&cur->suspendLock);      /*       * In that particular case we have to release the mutex on the thread list       * because it may cause deadlocks in the GC thread. It does not hurt as we       * do not access the thread list but we will have to reacquire it before       * returning.       */      if (cur->blockState & BS_THREAD)	      pthread_mutex_unlock(&activeThreadsLock);    }  /* freeze until we get a subsequent sigResume */  while( cur->suspendState == SS_SUSPENDED )    {      sigwait( &suspendSet, &s);      /* Post something even if it is not the right thread. */      if (cur->suspendState == SS_SUSPENDED)        repsem_post(&critSem);    }    DBG( JTHREADDETAIL, dprintf("sigwait return: %p\n", cur));  /* If the thread needs to be put back in a block state   * we must not reset the stack pointer.   */  if (state == 0)    cur->stackCur     = NULL;  cur->suspendState = 0;  cur->blockState |= state;    /* notify the critSect owner we are leaving the handler */  repsem_post( &critSem);  if (releaseMutex)    {      if (cur->blockState & BS_THREAD)	pthread_mutex_lock(&activeThreadsLock);      pthread_sigmask(SIG_SETMASK, &oldset, NULL);    }}/** * The suspend signal handler, which we need to implement critical sections. * It is used for two purposes: (a) to block all active threads which might * get rescheduled during a critical section (we can't rely on priority-fifo * scheduling, it might be SCHED_OTHER), and (b) to get a GC-limit of the current * thread stack so that we don't have to scan the whole thing. Since this * assumes that we execute on the threads normal stack, make sure we have no * SA_ONSTACK / signalstack() in effect */voidsuspend_signal_handler (int sig UNUSED){  volatile jthread_t   cur = jthread_current();  DBG( JTHREAD, dprintf("suspend signal handler: %p\n", cur));  /* signals are global things and might come from everywhere, anytime */  if ( !cur || !cur->active )	return;  KaffePThread_AckAndWaitForResume(cur, 0);}void KaffePThread_AckAndWaitForResume(volatile jthread_t cur, unsigned int state){  if ( cur->suspendState == SS_PENDING_SUSPEND ){    JTHREAD_JMPBUF env;        /*     * Note: We're not gonna do a longjmp to this place, we just want     * to do something that will save all of the registers onto the stack.     */    JTHREAD_SETJMP(env);        /* assuming we are executing on the thread stack, we record our current pos */    cur->stackCur     = (void*)&env;    cur->suspendState = SS_SUSPENDED;    cur->blockState  &= ~state;        /* notify the critSect owner that we are now suspending in the handler */    repsem_post( &critSem);        KaffePThread_WaitForResume(false, state);  }}/** * The resume signal handler, which we mainly need to get the implicit sigreturn * call (i.e. to unblock a preceeding sigwait). */voidresume_signal_handler ( int sig UNUSED ){  /* we don't do anything, here - all the action is in the suspend handler */}/** * Temporarily suspend all threads but the current one. This is * a dangerous operation, but it is more safe than to rely on * fixed priority scheduling (which most desktop OSes don't provide). * Make sure no suspended thread blocks on a resource (mutexed non-reentrant * lib func) we use within the critical section, or we have a classical deadlock. * Critical section can be nested, but that's usually not a good idea (increases * chances for deadlocks or trojan threads) */voidjthread_suspendall (void){  jthread_t	cur = jthread_current();  volatile jthread_t	t;  if (!jthreadInitialized)    return;   /* don't allow any new thread to be created or recycled until this is done */  protectThreadList(cur);  DBG( JTHREAD, dprintf("enter crit section[%d] from: %p [tid:%4ld, java:%p)\n",			critSection, cur, (unsigned long)cur->tid,			cur->data.jlThread));  if ( ++critSection == 1 ){#if !defined(KAFFE_BOEHM_GC)        int status;	int val;	int numPending = 0;	repsem_getvalue(&critSem, &val);	assert(val == 0);	for ( t=activeThreads; t; t = t->next ){	  /*	   * make sure we don't suspend ourselves, and we don't expect suspend	   * signals handled by threads which are blocked on someting else	   * than the thread lock (which we soon release)	   */	  pthread_mutex_lock(&t->suspendLock);	  if ( (t != cur) && (t->suspendState == 0) && (t->active != 0) ) {		DBG( JTHREAD, dprintf("signal suspend: %p (susp: %d blk: %d)\n",				      t, t->suspendState, t->blockState));		t->suspendState = SS_PENDING_SUSPEND;		if ((t->blockState & (BS_SYSCALL|BS_CV|BS_MUTEX|BS_CV_TO)) != 0)		  {		    /* The thread is already stopped.		     */		    assert(t->stackCur != NULL);		    t->suspendState = SS_SUSPENDED;		  }		else		  {		    if ((status = pthread_kill( t->tid, sigSuspend)) != 0)		      {			dprintf("Internal error: error sending SUSPEND signal to %p: %d (%s)\n", t, status, strerror(status));			KAFFEVM_ABORT();		      }		    else		      {			/* BAD: Empirical workaround for lost signals (with accumulative syncing)			 * It shouldn't be necessary (posix sems are accumulative), and it			 * is bad, performancewise (at least n*2 context switches per suspend)			 * but it works more reliably on linux 2.2.x */			numPending++;		      }		  }	  }	  pthread_mutex_unlock(&t->suspendLock);	}	/* Now that all signals has been sent we may wait for all concerned	 * threads to handle them.	 */	while (numPending > 0)	  {	    repsem_wait( &critSem);	    numPending--;	  }#else	/*	 * Here, we must use the special Boehm's stop world routine.	 * However we continue to update our own thread state flag.	 */	GC_disable();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -