Esempio n. 1
0
/**
 * gda_worker_new: (skip)
 *
 * Creates a new #GdaWorker object.
 *
 * Returns: (transfer full): a new #GdaWorker, or %NULL if an error occurred
 *
 * Since: 6.0
 */
GdaWorker *
gda_worker_new (void)
{
	GdaWorker *worker;
	worker = bg_get_spare_gda_worker ();
	if (worker)
		return worker;

	worker = g_slice_new0 (GdaWorker);
	worker->submit_its = itsignaler_new ();
	if (!worker->submit_its) {
		g_slice_free (GdaWorker, worker);
		return NULL;
	}

	worker->ref_count = 1;

	worker->callbacks_hash = g_hash_table_new_full (NULL, NULL, NULL,
							(GDestroyNotify) declared_callback_free);
	worker->jobs_hash = g_hash_table_new_full (g_int_hash, g_int_equal, NULL, (GDestroyNotify) worker_job_free);

	worker->worker_must_quit = 0;
	worker->location = NULL;

	g_rec_mutex_init (& worker->rmutex);

	gchar *str;
	static guint counter = 0;
	str = g_strdup_printf ("gdaWrkrTh%u", counter);
	counter++;
	worker->worker_thread = g_thread_try_new (str, (GThreadFunc) worker_thread_main, worker, NULL);
	g_free (str);
	if (!worker->worker_thread) {
		itsignaler_unref (worker->submit_its);
		g_hash_table_destroy (worker->callbacks_hash);
		g_hash_table_destroy (worker->jobs_hash);
		g_rec_mutex_clear (& worker->rmutex);
		g_slice_free (GdaWorker, worker);
		return NULL;
	}
	else
		bg_update_stats (BG_STARTED_THREADS);

#ifdef DEBUG_NOTIFICATION
	g_print ("[W] created GdaWorker %p\n", worker);
#endif

	bg_update_stats (BG_CREATED_WORKER);
	return worker;
}
Esempio n. 2
0
void thread_exit(void *ret)
{
  thread_t *t = current_thread;

  sanity_check_threadcounts();
  tdebug("current=%s\n", current_thread?current_thread->name : "NULL");

  if (current_thread == main_thread && main_exited == 0) {
	// the case when the user calls thread_exit() in main thread is complicated
	// we cannot simply terminate the main thread, because we need that stack to terminate the
	// whole program normally.  so we call exit() to make the c runtime help us get the stack
	// context where we can just return to terminate the whole program
	// this will call exit_func() and in turn call thread_exit() again
    main_exited = 1;
  	exit (0);		
  }

  // note the thread exit in the blocking graph
  t->curr_stats.node = bg_exit_node;
  current_thread->prev_stats.node->num_here--;
  current_thread->curr_stats.node->num_here++;
  if( bg_save_stats ) {
    bg_update_stats();
  }
    
  // update thread counts
  num_runnable_threads--;
  if( t->daemon ) num_daemon_threads--;

  t->state = ZOMBIE;
  num_zombie_threads++;

  // deallocate the TCB
  // keep the thread, if the thread is Joinable, and we want the return value for something
  if ( !( t->joinable ) ) {
    // tell the scheduler thread to delete the current one
    current_thread_exited = 1;
  } else {
    t->ret = ret;
    if (t->join_thread)
      thread_resume(t->join_thread);
  }

  sanity_check_threadcounts();

  // squirrel away the stack limit--not that we'll need it again
  current_thread->stack_bottom = stack_bottom;
  current_thread->stack_fingerprint = stack_fingerprint;

  // give control back to the scheduler
#ifdef NO_SCHEDULER_THREAD
  do_scheduler(NULL);
#else
  co_call(scheduler_thread->coro, NULL);
#endif
}
Esempio n. 3
0
/*
 * main function of the worker thread
 */
static gpointer
worker_thread_main (GdaWorker *worker)
{
#define TIMER 150
#ifdef DEBUG_NOTIFICATION
	g_print ("[W] GdaWorker %p, worker thread %p started!\n", worker, g_thread_self());
#endif
	itsignaler_ref (worker->submit_its);
	while (1) {
		WorkerJob *job;
		job = itsignaler_pop_notification (worker->submit_its, TIMER);
		if (job) {
			g_rec_mutex_lock (&worker->rmutex);
			if (! (job->status & JOB_CANCELLED)) {
				/* handle job */
				job->status |= JOB_BEING_PROCESSED;
				g_rec_mutex_unlock (&worker->rmutex);

				job->result = job->func (job->data, & job->error);

				g_rec_mutex_lock (&worker->rmutex);
				job->status |= JOB_PROCESSED;
				if (job->reply_its)
					itsignaler_push_notification (job->reply_its, job, NULL);
			}

			if ((job->status & JOB_CANCELLED) && worker->jobs_hash)
				g_hash_table_remove (worker->jobs_hash, &job->id);
			g_rec_mutex_unlock (&worker->rmutex);
		}

		if (worker->worker_must_quit) {
#ifdef DEBUG_NOTIFICATION
			g_print ("[W] GdaWorker %p, worker thread %p finished!\n", worker, g_thread_self());
#endif
			itsignaler_unref (worker->submit_its);
			g_rec_mutex_clear (& worker->rmutex);
			g_slice_free (GdaWorker, worker);
			bg_update_stats (BG_DESTROYED_WORKER);

			bg_join_thread ();
			return NULL;
		}
	}
	return NULL;
}
Esempio n. 4
0
/**
 * perform necessary management to yield the current thread
 * if suspended == TRUE && timeout != 0 -> the thread is added 
 * to the sleep queue and later waken up when the clock times out
 * returns FALSE if time-out actually happens, TRUE if waken up
 * by other threads, INTERRUPTED if interrupted by a signal
 **/
static int thread_yield_internal(int suspended, unsigned long long timeout)
{
// now we use a per-thread errno stored in thread_t
   int savederrno;
  int rv = OK;

  tdebug("current_thread=%p\n",current_thread);

  savederrno = errno;

  // decide what to do with the thread
  if( !suspended ) // just add it to the runlist
    sched_add_thread( current_thread );
  else if( timeout ) // add to the sleep list
    sleepq_add_thread( current_thread, timeout);

  {
#ifdef SHOW_EDGE_TIMES
    cpu_tick_t start, end, rstart, rend;
    GET_CPU_TICKS(start);
    GET_REAL_CPU_TICKS(rstart);
#endif

    // figure out the current node in the graph
    if( !conf_no_stacktrace )
      bg_backtrace_set_node();
    // FIXME: fake out what cil would do...  current_thread->curr_stats.node = bg_dummy_node;

    // we should already have been told the node by CIL or directly by the programmer
    assert( current_thread->curr_stats.node != NULL );
    
    // update node counts
    current_thread->prev_stats.node->num_here--;
    current_thread->curr_stats.node->num_here++;
    
    // update the blocking graph info
    if( bg_save_stats )
      bg_update_stats();
  
#ifdef SHOW_EDGE_TIMES
    GET_CPU_TICKS(end);
    GET_REAL_CPU_TICKS(rend);
    {
      thread_stats_t *curr = &current_thread->curr_stats;
      thread_stats_t *prev = &current_thread->prev_stats;
      output(" %3d -> %-3d     %7lld ticks  (%lld ms)   %7lld rticks (%lld ms)    ", 
             prev->node->node_num,  curr->node->node_num, 
             curr->cpu_ticks - prev->cpu_ticks,
             (curr->cpu_ticks - prev->cpu_ticks) / ticks_per_millisecond,
# ifdef USE_PERFCTR
             curr->real_ticks - prev->real_ticks,
             (curr->real_ticks - prev->real_ticks) / ticks_per_millisecond
# else
             curr->cpu_ticks - prev->cpu_ticks,
             (curr->cpu_ticks - prev->cpu_ticks) / ticks_per_millisecond
# endif
             );

      output("update bg node %d:   %lld   (%lld ms)   real: %lld (%lld ms)\n", 
             current_thread->curr_stats.node->node_num, 
             (end-start), (end-start)/ticks_per_millisecond, 
             (rend-rstart), (rend-rstart)/ticks_per_millisecond);
    }
#endif
  }

  // squirrel away the stack limit for next time
  current_thread->stack_bottom = stack_bottom;
  current_thread->stack_fingerprint = stack_fingerprint;

  // switch to the scheduler thread
#ifdef NO_SCHEDULER_THREAD
  do_scheduler(NULL);
#else
  co_call(scheduler_thread->coro, NULL);
#endif
  
  // set up stack limit for new thread
  stack_bottom = current_thread->stack_bottom;
  stack_fingerprint = current_thread->stack_fingerprint;

  // rotate the stats
  if( bg_save_stats ) {
    current_thread->prev_stats = current_thread->curr_stats;
    
    // update thread time, to skip time asleep
    GET_CPU_TICKS( current_thread->prev_stats.cpu_ticks );
    current_thread->prev_stats.cpu_ticks -= ticks_diff;  // FIXME: subtract out time to do debug output
#ifdef USE_PERFCTR
    GET_REAL_CPU_TICKS( current_thread->prev_stats.real_ticks );
    current_thread->prev_stats.real_ticks -= ticks_rdiff;  // FIXME: subtract out time to do debug output
#endif    
  } else {
    current_thread->prev_stats.node = current_thread->curr_stats.node;
  }
  
  // check whether time-out happens
  if (suspended && timeout && current_thread->timeout) {
    rv = TIMEDOUT;
    current_thread->timeout = 0;
  }

  // check for and process pending signals
  if ( likely(!current_thread->sig_waiting) ) {
  	if (sig_process_pending())
		rv = INTERRUPTED;
  } else {
	// if sig_waiting is 1, sigwait() itself will handle the remaining	
	rv = INTERRUPTED;
  }
  
  errno = savederrno;
  return rv;
}