static void async_invoke_thread (gpointer data) { MonoDomain *domain; MonoWSQ *wsq; ThreadPool *tp; gboolean must_die; tp = data; wsq = NULL; if (!tp->is_io) wsq = add_wsq (); set_tp_thread_info (tp); if (tp_start_func) tp_start_func (tp_hooks_user_data); data = NULL; for (;;) { MonoAsyncResult *ar; MonoClass *klass; gboolean is_io_task; gboolean is_socket; int n_naps = 0; is_io_task = FALSE; ar = (MonoAsyncResult *) data; if (ar) { InterlockedIncrement (&tp->busy_threads); domain = ((MonoObject *)ar)->vtable->domain; #ifndef DISABLE_SOCKETS klass = ((MonoObject *) data)->vtable->klass; is_io_task = !is_corlib_asyncresult (domain, klass); is_socket = FALSE; if (is_io_task) { MonoSocketAsyncResult *state = (MonoSocketAsyncResult *) data; is_socket = is_socketasyncresult (domain, klass); ar = state->ares; switch (state->operation) { case AIO_OP_RECEIVE: state->total = ICALL_RECV (state); break; case AIO_OP_SEND: state->total = ICALL_SEND (state); break; } } #endif /* worker threads invokes methods in different domains, * so we need to set the right domain here */ g_assert (domain); if (mono_domain_is_unloading (domain) || mono_runtime_is_shutting_down ()) { threadpool_jobs_dec ((MonoObject *)ar); data = NULL; ar = NULL; InterlockedDecrement (&tp->busy_threads); } else { mono_thread_push_appdomain_ref (domain); if (threadpool_jobs_dec ((MonoObject *)ar)) { data = NULL; ar = NULL; mono_thread_pop_appdomain_ref (); InterlockedDecrement (&tp->busy_threads); continue; } if (mono_domain_set (domain, FALSE)) { MonoObject *exc; if (tp_item_begin_func) tp_item_begin_func (tp_item_user_data); exc = mono_async_invoke (tp, ar); if (tp_item_end_func) tp_item_end_func (tp_item_user_data); if (exc) mono_internal_thread_unhandled_exception (exc); if (is_socket && tp->is_io) { MonoSocketAsyncResult *state = (MonoSocketAsyncResult *) data; if (state->completed && state->callback) { MonoAsyncResult *cb_ares; cb_ares = create_simple_asyncresult ((MonoObject *) state->callback, (MonoObject *) state); icall_append_job ((MonoObject *) cb_ares); } } mono_domain_set (mono_get_root_domain (), TRUE); } mono_thread_pop_appdomain_ref (); InterlockedDecrement (&tp->busy_threads); clear_thread_state (); } } ar = NULL; data = NULL; must_die = should_i_die (tp); if (must_die) { mono_wsq_suspend (wsq); } else { if (tp->is_io || !mono_wsq_local_pop (&data)) dequeue_or_steal (tp, &data, wsq); } n_naps = 0; while (!must_die && !data && n_naps < 4) { gboolean res; InterlockedIncrement (&tp->waiting); // Another thread may have added a job into its wsq since the last call to dequeue_or_steal // Check all the queues again before entering the wait loop dequeue_or_steal (tp, &data, wsq); if (data) { InterlockedDecrement (&tp->waiting); break; } mono_gc_set_skip_thread (TRUE); #if defined(__OpenBSD__) while (mono_cq_count (tp->queue) == 0 && (res = mono_sem_wait (&tp->new_job, TRUE)) == -1) {// && errno == EINTR) { #else while (mono_cq_count (tp->queue) == 0 && (res = mono_sem_timedwait (&tp->new_job, 2000, TRUE)) == -1) {// && errno == EINTR) { #endif if (mono_runtime_is_shutting_down ()) break; check_for_interruption_critical (); } InterlockedDecrement (&tp->waiting); mono_gc_set_skip_thread (FALSE); if (mono_runtime_is_shutting_down ()) break; must_die = should_i_die (tp); dequeue_or_steal (tp, &data, wsq); n_naps++; } if (!data && !tp->is_io && !mono_runtime_is_shutting_down ()) { mono_wsq_local_pop (&data); if (data && must_die) { InterlockedCompareExchange (&tp->destroy_thread, 1, 0); pulse_on_new_job (tp); } } if (!data) { gint nt; gboolean down; while (1) { nt = tp->nthreads; down = mono_runtime_is_shutting_down (); if (!down && nt <= tp->min_threads) break; if (down || InterlockedCompareExchange (&tp->nthreads, nt - 1, nt) == nt) { #ifndef DISABLE_PERFCOUNTERS mono_perfcounter_update_value (tp->pc_nthreads, TRUE, -1); #endif if (!tp->is_io) { remove_wsq (wsq); } fire_profiler_thread_end (); if (tp_finish_func) tp_finish_func (tp_hooks_user_data); if (!tp->is_io) { if (threads) { mono_mutex_lock (&threads_lock); if (threads) g_ptr_array_remove_fast (threads, mono_thread_current ()->internal_thread); mono_mutex_unlock (&threads_lock); } } return; } } } } g_assert_not_reached (); } void ves_icall_System_Threading_ThreadPool_GetAvailableThreads (gint *workerThreads, gint *completionPortThreads) { *workerThreads = async_tp.max_threads - async_tp.busy_threads; *completionPortThreads = async_io_tp.max_threads - async_io_tp.busy_threads; }
static void pre_fuzz_handler(void *wrapcxt, INOUT void **user_data) { void *dcontext = drwrap_get_drcontext(wrapcxt); app_pc target_to_fuzz = drwrap_get_func(wrapcxt); fuzz_target_t *target = hashtable_lookup(&fuzz_target_htable, target_to_fuzz); fuzz_pass_context_t *fp = (fuzz_pass_context_t *) drmgr_get_tls_field(dcontext, tls_idx_fuzzer); bool is_target_entry = false; pass_target_t *live = NULL; dr_mcontext_t *mc; uint i; ASSERT(target != NULL, "pre_fuzz must be associated with a fuzz target"); DRFUZZ_LOG(3, "pre_fuzz() for target "PFX" with %d args\n", target_to_fuzz, target->arg_count); /* XXX i#1734: this heuristic may be incorrect when a handled fault occurs during * the very last iteration of the last fuzz pass on any thread. */ clear_thread_state(fp); /* Stop the target iterator that was captured at the last critical fault, because * the fact that we are in pre-fuzz implies the fault was handled and doesn't matter. */ if (fp->thread_state->targets != NULL) drfuzz_target_iterator_stop(fp->thread_state->targets); /* XXX: assumes the fuzz target is never called recursively */ if (fp->live_targets != NULL && fp->live_targets->target->func_pc == target_to_fuzz) { live = fp->live_targets; /* this is a repetition of the last live target */ } else { is_target_entry = true; /* this is a new invocation of a target */ live = activate_cached_target(fp, target_to_fuzz); /* check the cache */ if (live == NULL) live = create_pass_target(dcontext, wrapcxt); live->next = fp->live_targets; /* push to live stack */ fp->live_targets = live; } /* required by dr_redirect_execution() (avoids having to merge the mcontext) */ mc = drwrap_get_mcontext_ex(wrapcxt, DR_MC_ALL); /* XXX: can we relax this? */ if (is_target_entry) { live->xsp = mc->xsp; #ifdef X86 live->unclobber.retaddr_loc = (reg_t *) mc->xsp; /* see retaddr_unclobber_t */ #endif live->unclobber.retaddr = (reg_t) drwrap_get_retaddr(wrapcxt); DRFUZZ_LOG(4, "fuzz target "PFX": saving stack pointer "PFX"\n", target_to_fuzz, mc->xsp); for (i = 0; i < target->arg_count; i++) { /* store the original arg values */ live->original_args[i] = (reg_t) drwrap_get_arg(wrapcxt, i); /* copy original args to current args for the first iteration of the fuzz */ live->current_args[i] = live->original_args[i]; DRFUZZ_LOG(4, "fuzz target "PFX": saving original arg #%d: "PFX"\n", target_to_fuzz, i, live->original_args[i]); } } /* restore the original arg values before calling the client */ for (i = 0; i < target->arg_count; i++) { DRFUZZ_LOG(4, "fuzz target "PFX": restoring original arg #%d: "PFX"\n", target_to_fuzz, i, live->original_args[i]); drwrap_set_arg(wrapcxt, i, (void *) live->original_args[i]); } #ifdef ARM mc->lr = live->unclobber.retaddr; /* restore retaddr to link register */ #else /* X86 */ *live->unclobber.retaddr_loc = live->unclobber.retaddr; /* restore retaddr to stack */ #endif target->pre_fuzz_cb(fp, (generic_func_t) target_to_fuzz, mc); drwrap_set_mcontext(wrapcxt); for (i = 0; i < target->arg_count; i++) live->current_args[i] = (reg_t) drwrap_get_arg(wrapcxt, i); *user_data = fp; }