static void test_procmon_tor_process_monitor_new(void *ignored) { (void)ignored; tor_process_monitor_t *res; const char *msg; res = tor_process_monitor_new(NULL, "probably invalid", 0, NULL, NULL, &msg); tt_assert(!res); tt_str_op(msg, OP_EQ, "invalid PID"); res = tor_process_monitor_new(NULL, "243443535345454", 0, NULL, NULL, &msg); tt_assert(!res); tt_str_op(msg, OP_EQ, "invalid PID"); res = tor_process_monitor_new(tor_libevent_get_base(), "43", 0, NULL, NULL, &msg); tt_assert(res); tt_assert(!msg); res = tor_process_monitor_new(tor_libevent_get_base(), "44 hello", 0, NULL, NULL, &msg); tt_assert(res); tt_assert(!msg); res = tor_process_monitor_new(tor_libevent_get_base(), "45:hello", 0, NULL, NULL, &msg); tt_assert(res); tt_assert(!msg); done: (void)0; }
static int add_n_work_items(threadpool_t *tp, int n) { int n_queued = 0; int n_try_cancel = 0, i; workqueue_entry_t **to_cancel; workqueue_entry_t *ent; to_cancel = tor_malloc(sizeof(workqueue_entry_t*) * opt_n_cancel); while (n_queued++ < n) { ent = add_work(tp); if (! ent) { tor_event_base_loopexit(tor_libevent_get_base(), NULL); return -1; } if (n_try_cancel < opt_n_cancel && tor_weak_random_range(&weak_rng, n) < opt_n_cancel) { to_cancel[n_try_cancel++] = ent; } } for (i = 0; i < n_try_cancel; ++i) { void *work = workqueue_entry_cancel(to_cancel[i]); if (! work) { n_failed_cancel++; } else { n_successful_cancel++; tor_free(work); } } tor_free(to_cancel); return 0; }
static void replysock_readable_cb(tor_socket_t sock, short what, void *arg) { threadpool_t *tp = arg; replyqueue_t *rq = threadpool_get_replyqueue(tp); int old_r = n_received; (void) sock; (void) what; replyqueue_process(rq); if (old_r == n_received) return; if (opt_verbose) { printf("%d / %d", n_received, n_sent); if (opt_n_cancel) printf(" (%d cancelled, %d uncancellable)", n_successful_cancel, n_failed_cancel); puts(""); } #ifdef TRACK_RESPONSES tor_mutex_acquire(&bitmap_mutex); for (i = 0; i < opt_n_items; ++i) { if (bitarray_is_set(received, i)) putc('o', stdout); else if (bitarray_is_set(handled, i)) putc('!', stdout); else putc('.', stdout); } puts(""); tor_mutex_release(&bitmap_mutex); #endif if (n_sent - (n_received+n_successful_cancel) < opt_n_lowwater) { int n_to_send = n_received + opt_n_inflight - n_sent; if (n_to_send > opt_n_items - n_sent) n_to_send = opt_n_items - n_sent; add_n_work_items(tp, n_to_send); } if (shutting_down == 0 && n_received+n_successful_cancel == n_sent && n_sent >= opt_n_items) { shutting_down = 1; threadpool_queue_update(tp, NULL, workqueue_do_shutdown, NULL, NULL); // Anything we add after starting the shutdown must not be executed. threadpool_queue_work(tp, workqueue_shutdown_error, handle_reply_shutdown, NULL); { struct timeval limit = { 2, 0 }; tor_event_base_loopexit(tor_libevent_get_base(), &limit); } } }
/** Work-alike replacement for event_new() on pre-Libevent-2.0 systems. */ struct event * tor_event_new(struct event_base *base, int sock, short what, void (*cb)(int, short, void *), void *arg) { struct event *e = tor_malloc_zero(sizeof(struct event)); event_set(e, sock, what, cb, arg); if (! base) base = tor_libevent_get_base(); event_base_set(base, e); return e; }
/** Initialize the common timeout that we'll use to refill the buckets every * time a tick elapses. */ static void tor_libevent_set_tick_timeout(int msec_per_tick) { struct event_base *base = tor_libevent_get_base(); struct timeval tv; tor_assert(! one_tick); tv.tv_sec = msec_per_tick / 1000; tv.tv_usec = (msec_per_tick % 1000) * 1000; one_tick = event_base_init_common_timeout(base, &tv); }
/** Initializes the libevent backend for a periodic event. */ void periodic_event_setup(periodic_event_item_t *event) { if (event->ev) { /* Already setup? This is a bug */ log_err(LD_BUG, "Initial dispatch should only be done once."); tor_assert(0); } event->ev = tor_event_new(tor_libevent_get_base(), -1, 0, periodic_event_dispatch, event); tor_assert(event->ev); }
/** Handles service control requests, such as stopping or starting the * Tor service. */ static void nt_service_control(DWORD request) { static struct timeval exit_now; exit_now.tv_sec = 0; exit_now.tv_usec = 0; nt_service_loadlibrary(); switch (request) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: log_notice(LD_GENERAL, "Got stop/shutdown request; shutting down cleanly."); service_status.dwCurrentState = SERVICE_STOP_PENDING; event_base_loopexit(tor_libevent_get_base(), &exit_now); return; } service_fns.SetServiceStatus_fn(hStatus, &service_status); }
static void timer_cb(tor_timer_t *t, void *arg, const monotime_t *now_mono) { struct timeval now; tor_gettimeofday(&now); tor_timer_t **t_ptr = arg; tor_assert(*t_ptr == t); int idx = (int) (t_ptr - timers); ++fired[idx]; timersub(&now, &fire_at[idx], &difference[idx]); diffs_mono_usec[idx] = monotime_diff_usec(&started_at, now_mono) - delay_usec[idx]; ++n_fired; // printf("%d / %d\n",n_fired, N_TIMERS); if (n_fired == n_active_timers) { tor_libevent_exit_loop_after_callback(tor_libevent_get_base()); } }
/** * Initialize the timers subsystem. Requires that libevent has already been * initialized. */ void timers_initialize(void) { if (BUG(global_timeouts)) return; // LCOV_EXCL_LINE timeout_error_t err; global_timeouts = timeouts_open(0, &err); if (!global_timeouts) { // LCOV_EXCL_START -- this can only fail on malloc failure. log_err(LD_BUG, "Unable to open timer backend: %s", strerror(err)); tor_assert(0); // LCOV_EXCL_STOP } struct event *timer_event; timer_event = tor_event_new(tor_libevent_get_base(), -1, 0, libevent_timer_callback, NULL); tor_assert(timer_event); global_timer_event = timer_event; libevent_timer_reschedule(); }
/** This function sets the file descriptor in the <b>handle</b> as non-blocking * and configures the libevent event structure based on the given <b>flags</b> * to ensure that <b>callback</b> is called whenever we have events on the * given <b>handle</b>. */ STATIC void process_unix_setup_handle(process_t *process, process_unix_handle_t *handle, short flags, event_callback_fn callback) { tor_assert(process); tor_assert(handle); tor_assert(callback); /* Put our file descriptor into non-blocking mode. */ if (fcntl(handle->fd, F_SETFL, O_NONBLOCK) < 0) { log_warn(LD_PROCESS, "Unable mark Unix handle as non-blocking: %s", strerror(errno)); } /* Setup libevent event. */ handle->event = tor_event_new(tor_libevent_get_base(), handle->fd, flags, callback, process); }
/* * normally tor calls event_base_loopexit so control returns from the libevent * event loop back to the tor main loop. tor then activates "linked" socket * connections before returning back to the libevent event loop. * * we hijack and use the libevent loop in nonblock mode, so when tor calls * the loopexit, we basically just need to do the linked connection activation. * that is extracted to scalliontor_loopexitCallback, which we need to execute * as a callback so we don't invoke event_base_loop while it is currently being * executed. */ static void scalliontor_loopexitCallback(ScallionTor* stor) { update_approx_time(time(NULL)); scalliontor_notify(stor); while(1) { /* All active linked conns should get their read events activated. */ SMARTLIST_FOREACH(active_linked_connection_lst, connection_t *, conn, event_active(conn->read_event, EV_READ, 1)); /* if linked conns are still active, enter libevent loop using EVLOOP_ONCE */ called_loop_once = smartlist_len(active_linked_connection_lst) ? 1 : 0; if(called_loop_once) { event_base_loop(tor_libevent_get_base(), EVLOOP_ONCE|EVLOOP_NONBLOCK); } else { /* linked conns are done */ break; } } /* make sure we handle any new events caused by the linked conns */ scalliontor_notify(stor); }
void scalliontor_newCPUWorker(ScallionTor* stor, int fd) { g_assert(stor); if(stor->cpuw) { g_free(stor->cpuw); } vtor_cpuworker_tp cpuw = calloc(1, sizeof(vtor_cpuworker_t)); cpuw->fd = fd; cpuw->state = CPUW_NONE; #ifdef SCALLION_USEV2CPUWORKER cpuw->magic1 = SCALLION_CPUWORKER_MAGIC1; cpuw->magic2 = SCALLION_CPUWORKER_MAGIC2; cpuw->magic3 = SCALLION_CPUWORKER_MAGIC3; setup_server_onion_keys(&(cpuw->onion_keys)); #else dup_onion_keys(&(cpuw->onion_key), &(cpuw->last_onion_key)); #endif /* setup event so we will get a callback */ event_assign(&(cpuw->read_event), tor_libevent_get_base(), cpuw->fd, EV_READ|EV_PERSIST, scalliontor_readCPUWorkerCallback, cpuw); event_add(&(cpuw->read_event), NULL); }
int main(int argc, char **argv) { replyqueue_t *rq; threadpool_t *tp; int i; tor_libevent_cfg evcfg; struct event *ev; uint32_t as_flags = 0; for (i = 1; i < argc; ++i) { if (!strcmp(argv[i], "-v")) { opt_verbose = 1; } else if (!strcmp(argv[i], "-T") && i+1<argc) { opt_n_threads = atoi(argv[++i]); } else if (!strcmp(argv[i], "-N") && i+1<argc) { opt_n_items = atoi(argv[++i]); } else if (!strcmp(argv[i], "-I") && i+1<argc) { opt_n_inflight = atoi(argv[++i]); } else if (!strcmp(argv[i], "-L") && i+1<argc) { opt_n_lowwater = atoi(argv[++i]); } else if (!strcmp(argv[i], "-R") && i+1<argc) { opt_ratio_rsa = atoi(argv[++i]); } else if (!strcmp(argv[i], "-C") && i+1<argc) { opt_n_cancel = atoi(argv[++i]); } else if (!strcmp(argv[i], "--no-eventfd2")) { as_flags |= ASOCKS_NOEVENTFD2; } else if (!strcmp(argv[i], "--no-eventfd")) { as_flags |= ASOCKS_NOEVENTFD; } else if (!strcmp(argv[i], "--no-pipe2")) { as_flags |= ASOCKS_NOPIPE2; } else if (!strcmp(argv[i], "--no-pipe")) { as_flags |= ASOCKS_NOPIPE; } else if (!strcmp(argv[i], "--no-socketpair")) { as_flags |= ASOCKS_NOSOCKETPAIR; } else if (!strcmp(argv[i], "-h")) { help(); return 0; } else { help(); return 1; } } if (opt_n_threads < 1 || opt_n_items < 1 || opt_n_inflight < 1 || opt_n_lowwater < 0 || opt_n_cancel > opt_n_inflight || opt_n_inflight > MAX_INFLIGHT || opt_ratio_rsa < 0) { help(); return 1; } init_logging(1); crypto_global_init(1, NULL, NULL); crypto_seed_rng(1); rq = replyqueue_new(as_flags); tor_assert(rq); tp = threadpool_new(opt_n_threads, rq, new_state, free_state, NULL); tor_assert(tp); crypto_seed_weak_rng(&weak_rng); memset(&evcfg, 0, sizeof(evcfg)); tor_libevent_initialize(&evcfg); ev = tor_event_new(tor_libevent_get_base(), replyqueue_get_socket(rq), EV_READ|EV_PERSIST, replysock_readable_cb, tp); event_add(ev, NULL); #ifdef TRACK_RESPONSES handled = bitarray_init_zero(opt_n_items); received = bitarray_init_zero(opt_n_items); tor_mutex_init(&bitmap_mutex); handled_len = opt_n_items; #endif for (i = 0; i < opt_n_inflight; ++i) { if (! add_work(tp)) { puts("Couldn't add work."); return 1; } } { struct timeval limit = { 30, 0 }; tor_event_base_loopexit(tor_libevent_get_base(), &limit); } event_base_loop(tor_libevent_get_base(), 0); if (n_sent != opt_n_items || n_received+n_successful_cancel != n_sent) { printf("%d vs %d\n", n_sent, opt_n_items); printf("%d+%d vs %d\n", n_received, n_successful_cancel, n_sent); puts("FAIL"); return 1; } else { puts("OK"); return 0; } }
int main(int argc, char **argv) { (void)argc; (void)argv; tor_libevent_cfg cfg; memset(&cfg, 0, sizeof(cfg)); tor_libevent_initialize(&cfg); timers_initialize(); int i; int ret; struct timeval now; tor_gettimeofday(&now); monotime_get(&started_at); for (i = 0; i < N_TIMERS; ++i) { struct timeval delay; delay.tv_sec = crypto_rand_int_range(0,MAX_DURATION); delay.tv_usec = crypto_rand_int_range(0,1000000); delay_usec[i] = delay.tv_sec * 1000000 + delay.tv_usec; timeradd(&now, &delay, &fire_at[i]); timers[i] = timer_new(timer_cb, &timers[i]); timer_schedule(timers[i], &delay); ++n_active_timers; } /* Disable some; we'll make sure they don't trigger. */ for (i = 0; i < N_DISABLE; ++i) { int idx = crypto_rand_int_range(0, N_TIMERS); if (is_disabled[idx]) continue; is_disabled[idx] = 1; timer_disable(timers[idx]); --n_active_timers; } tor_libevent_run_event_loop(tor_libevent_get_base(), 0); int64_t total_difference = 0; uint64_t total_square_difference = 0; tor_assert(n_fired == n_active_timers); for (i = 0; i < N_TIMERS; ++i) { if (is_disabled[i]) { tor_assert(fired[i] == 0); continue; } tor_assert(fired[i] == 1); //int64_t diff = difference[i].tv_usec + difference[i].tv_sec * 1000000; int64_t diff = diffs_mono_usec[i]; total_difference += diff; total_square_difference += diff*diff; } const int64_t mean_diff = total_difference / n_active_timers; printf("mean difference: "I64_FORMAT" usec\n", I64_PRINTF_ARG(mean_diff)); const double mean_sq = ((double)total_square_difference)/ n_active_timers; const double sq_mean = mean_diff * mean_diff; const double stddev = sqrt(mean_sq - sq_mean); printf("standard deviation: %lf usec\n", stddev); #define MAX_DIFF_USEC (500*1000) #define MAX_STDDEV_USEC (500*1000) #define ODD_DIFF_USEC (2000) #define ODD_STDDEV_USEC (2000) if (mean_diff < 0 || mean_diff > MAX_DIFF_USEC || stddev > MAX_STDDEV_USEC) { printf("Either your system is under ridiculous load, or the " "timer backend is broken.\n"); ret = 1; } else if (mean_diff > ODD_DIFF_USEC || stddev > ODD_STDDEV_USEC) { printf("Either your system is a bit slow or the " "timer backend is odd.\n"); ret = 0; } else { printf("Looks good enough.\n"); ret = 0; } timer_free_(NULL); for (i = 0; i < N_TIMERS; ++i) { timer_free(timers[i]); } timers_shutdown(); return ret; }
void scalliontor_notify(ScallionTor* stor) { update_approx_time(time(NULL)); /* tell libevent to check epoll and activate the ready sockets without blocking */ event_base_loop(tor_libevent_get_base(), EVLOOP_NONBLOCK); }