/** * Queue RRset for signing. * */ static void worker_queue_rrset(worker_type* worker, fifoq_type* q, rrset_type* rrset) { ods_status status = ODS_STATUS_UNCHANGED; int tries = 0; ods_log_assert(worker); ods_log_assert(q); ods_log_assert(rrset); lock_basic_lock(&q->q_lock); status = fifoq_push(q, (void*) rrset, worker, &tries); while (status == ODS_STATUS_UNCHANGED) { tries++; if (worker->need_to_exit) { lock_basic_unlock(&q->q_lock); return; } /** * Apparently the queue is full. Lets take a small break to not hog CPU. * The worker will release the signq lock while sleeping and will * automatically grab the lock when the queue is nonfull. * Queue is nonfull at 10% of the queue size. */ lock_basic_sleep(&q->q_nonfull, &q->q_lock, 5); status = fifoq_push(q, (void*) rrset, worker, &tries); } lock_basic_unlock(&q->q_lock); ods_log_assert(status == ODS_STATUS_OK); lock_basic_lock(&worker->worker_lock); worker->jobs_appointed += 1; lock_basic_unlock(&worker->worker_lock); return; }
/** * Worker waiting. * */ void worker_wait_timeout(lock_basic_type* lock, cond_basic_type* condition, time_t timeout) { lock_basic_lock(lock); lock_basic_sleep(condition, lock, timeout); lock_basic_unlock(lock); return; }
/** * Worker waiting. * */ void worker_wait(lock_basic_type* lock, cond_basic_type* condition) { lock_basic_lock(lock); /* [LOCK] worker */ lock_basic_sleep(condition, lock, 0); /* [UNLOCK] worker */ lock_basic_unlock(lock); return; }
/** * Put worker to sleep. * */ void worker_sleep(worker_type* worker, time_t timeout) { ods_log_assert(worker); lock_basic_lock(&worker->worker_lock); worker->sleeping = 1; lock_basic_sleep(&worker->worker_alarm, &worker->worker_lock, timeout); lock_basic_unlock(&worker->worker_lock); return; }
/** * Run engine, run!. * */ static void engine_run(engine_type* engine, int single_run) { if (!engine) { return; } engine_start_workers(engine); engine_start_drudgers(engine); lock_basic_lock(&engine->signal_lock); engine->signal = SIGNAL_RUN; lock_basic_unlock(&engine->signal_lock); while (!engine->need_to_exit && !engine->need_to_reload) { lock_basic_lock(&engine->signal_lock); engine->signal = signal_capture(engine->signal); switch (engine->signal) { case SIGNAL_RUN: ods_log_assert(1); break; case SIGNAL_RELOAD: engine->need_to_reload = 1; break; case SIGNAL_SHUTDOWN: engine->need_to_exit = 1; break; default: ods_log_warning("[%s] invalid signal %d captured, " "keep running", engine_str, signal); engine->signal = SIGNAL_RUN; break; } lock_basic_unlock(&engine->signal_lock); if (single_run) { engine->need_to_exit = engine_all_zones_processed(engine); } lock_basic_lock(&engine->signal_lock); if (engine->signal == SIGNAL_RUN && !single_run) { ods_log_debug("[%s] taking a break", engine_str); lock_basic_sleep(&engine->signal_cond, &engine->signal_lock, 3600); } lock_basic_unlock(&engine->signal_lock); } ods_log_debug("[%s] signer halted", engine_str); engine_stop_drudgers(engine); engine_stop_workers(engine); (void)lhsm_reopen(engine->config->cfg_filename); return; }
/** * Put worker to sleep unless worker has measured up to all appointed jobs. * */ void worker_sleep_unless(worker_type* worker, time_t timeout) { ods_log_assert(worker); lock_basic_lock(&worker->worker_lock); /* [LOCK] worker */ if (!worker->need_to_exit && !worker_fulfilled(worker)) { worker->sleeping = 1; lock_basic_sleep(&worker->worker_alarm, &worker->worker_lock, timeout); } /* [UNLOCK] worker */ lock_basic_unlock(&worker->worker_lock); return; }
/** * Put worker to sleep unless worker has measured up to all appointed jobs. * */ void worker_sleep_unless(worker_type* worker, time_t timeout) { ods_log_assert(worker); lock_basic_lock(&worker->worker_lock); while (!worker->need_to_exit && !worker_fulfilled(worker)) { worker->sleeping = 1; lock_basic_sleep(&worker->worker_alarm, &worker->worker_lock, timeout); ods_log_debug("[%s[%i]] somebody poked me, check completed jobs %u " "appointed, %u completed, %u failed", worker2str(worker->type), worker->thread_num, worker->jobs_appointed, worker->jobs_completed, worker->jobs_failed); } lock_basic_unlock(&worker->worker_lock); return; }
/** * Put worker to sleep. * */ void worker_sleep(worker_type* worker, time_t timeout) { ods_log_assert(worker); lock_basic_lock(&worker->worker_lock); /* [LOCK] worker */ /** need_to_exit may be set after check in worker start * and alarm might be fired before worker_lock. This check * prevents possible deadlock */ if (!worker->need_to_exit) { worker->sleeping = 1; lock_basic_sleep(&worker->worker_alarm, &worker->worker_lock, timeout); } /* [UNLOCK] worker */ lock_basic_unlock(&worker->worker_lock); return; }
/** * Drudge. * */ static void worker_drudge(worker_type* worker) { engine_type* engine = NULL; zone_type* zone = NULL; task_type* task = NULL; rrset_type* rrset = NULL; ods_status status = ODS_STATUS_OK; worker_type* superior = NULL; hsm_ctx_t* ctx = NULL; ods_log_assert(worker); ods_log_assert(worker->engine); ods_log_assert(worker->type == WORKER_DRUDGER); engine = (engine_type*) worker->engine; while (worker->need_to_exit == 0) { ods_log_deeebug("[%s[%i]] report for duty", worker2str(worker->type), worker->thread_num); /* initialize */ superior = NULL; zone = NULL; task = NULL; /* get item */ lock_basic_lock(&engine->signq->q_lock); rrset = (rrset_type*) fifoq_pop(engine->signq, &superior); if (!rrset) { ods_log_deeebug("[%s[%i]] nothing to do, wait", worker2str(worker->type), worker->thread_num); /** * Apparently the queue is empty. Wait until new work is queued. * The drudger will release the signq lock while sleeping and * will automatically grab the lock when the threshold is reached. * Threshold is at 1 and MAX (after a number of tries). */ lock_basic_sleep(&engine->signq->q_threshold, &engine->signq->q_lock, 0); rrset = (rrset_type*) fifoq_pop(engine->signq, &superior); } lock_basic_unlock(&engine->signq->q_lock); /* do some work */ if (rrset) { ods_log_assert(superior); if (!ctx) { ods_log_debug("[%s[%i]] create hsm context", worker2str(worker->type), worker->thread_num); ctx = hsm_create_context(); } if (!ctx) { ods_log_crit("[%s[%i]] error creating libhsm context", worker2str(worker->type), worker->thread_num); engine->need_to_reload = 1; lock_basic_lock(&superior->worker_lock); superior->jobs_failed++; lock_basic_unlock(&superior->worker_lock); } else { ods_log_assert(ctx); lock_basic_lock(&superior->worker_lock); task = superior->task; ods_log_assert(task); zone = task->zone; lock_basic_unlock(&superior->worker_lock); ods_log_assert(zone); ods_log_assert(zone->apex); ods_log_assert(zone->signconf); worker->clock_in = time(NULL); status = rrset_sign(ctx, rrset, superior->clock_in); lock_basic_lock(&superior->worker_lock); if (status == ODS_STATUS_OK) { superior->jobs_completed++; } else { superior->jobs_failed++; } lock_basic_unlock(&superior->worker_lock); } if (worker_fulfilled(superior) && superior->sleeping) { ods_log_deeebug("[%s[%i]] wake up superior[%u], work is " "done", worker2str(worker->type), worker->thread_num, superior->thread_num); worker_wakeup(superior); } superior = NULL; rrset = NULL; } /* done work */ } /* wake up superior */ if (superior && superior->sleeping) { ods_log_deeebug("[%s[%i]] wake up superior[%u], i am exiting", worker2str(worker->type), worker->thread_num, superior->thread_num); worker_wakeup(superior); } /* cleanup open HSM sessions */ if (ctx) { hsm_destroy_context(ctx); } return; }
/** * Run engine, run!. * */ static void engine_run(engine_type* engine, start_cb_t start, int single_run) { if (!engine) { return; } ods_log_assert(engine); engine_start_workers(engine); engine_start_drudgers(engine); lock_basic_lock(&engine->signal_lock); /* [LOCK] signal */ engine->signal = SIGNAL_RUN; /* [UNLOCK] signal */ lock_basic_unlock(&engine->signal_lock); /* call the external start callback function */ start(engine); while (!engine->need_to_exit && !engine->need_to_reload) { lock_basic_lock(&engine->signal_lock); /* [LOCK] signal */ engine->signal = signal_capture(engine->signal); switch (engine->signal) { case SIGNAL_RUN: ods_log_assert(1); break; case SIGNAL_RELOAD: engine->need_to_reload = 1; break; case SIGNAL_SHUTDOWN: engine->need_to_exit = 1; break; default: ods_log_warning("[%s] invalid signal captured: %d, " "keep running", engine_str, signal); engine->signal = SIGNAL_RUN; break; } /* [UNLOCK] signal */ lock_basic_unlock(&engine->signal_lock); if (single_run) { engine->need_to_exit = 1; /* FIXME: all tasks need to terminate, then set need_to_exit to 1 */ } lock_basic_lock(&engine->signal_lock); /* [LOCK] signal */ if (engine->signal == SIGNAL_RUN && !single_run) { ods_log_debug("[%s] taking a break", engine_str); lock_basic_sleep(&engine->signal_cond, &engine->signal_lock, 3600); } /* [UNLOCK] signal */ lock_basic_unlock(&engine->signal_lock); } ods_log_debug("[%s] enforcer halted", engine_str); engine_stop_drudgers(engine); engine_stop_workers(engine); return; }