#define PTHREAD_MUTEX_UNLOCK
#endif
+/*
+ * Debugging, mainly for schedule_test
+ */
+#if 0
+#define MPRINT(...) fprintf(stdout, __VA_ARGS__)
+#else
+#define MPRINT(...)
+#endif
+
/*
* Other OS's have sem_init, OS X doesn't.
*/
typedef struct fr_schedule_worker_t {
pthread_t pthread_id; //!< the thread of this worker
+ int id; //!< a unique ID
int uses; //!< how many network threads are using it
fr_time_t cpu_time; //!< how much CPU time this worker has used
int heap_id; //!< for the heap of workers
fr_schedule_t *sc = sw->sc;
fr_schedule_child_status_t status = FR_CHILD_FAIL;
+ MPRINT("Worker %d starting\n", sw->id);
+
ctx = talloc_init("worker");
if (!ctx) goto fail;
sc->num_workers++;
PTHREAD_MUTEX_UNLOCK(&sc->mutex);
+ MPRINT("Worker %d running\n", sw->id);
+
/*
* Tell the originator that the thread has started.
*/
*/
fr_worker(sw->worker);
+ MPRINT("Worker %d finished\n", sw->id);
+
/*
* Talloc ordering issues. We want to be independent of
* how talloc walks it's children, and ensure that some
sc->num_workers_exited++;
PTHREAD_MUTEX_UNLOCK(&sc->mutex);
+ MPRINT("Worker %d exiting\n", sw->id);
+
/*
* Tell the scheduler we're done.
*/
}
sr->status = FR_CHILD_RUNNING;
+
+ /*
+ * Tell the originator that the thread has started.
+ */
sem_post(&sc->semaphore);
/*
for (i = 0; i < sc->max_workers; i++) {
fr_schedule_worker_t *sw;
+ MPRINT("Creating %d/%d workers\n", i, sc->max_workers);
+
/*
* Create a worker "glue" structure
*/
sw = talloc_zero(sc, fr_schedule_worker_t);
if (!sw) break;
+ sw->id = i;
sw->sc = sc;
sw->status = FR_CHILD_INITIALIZING;
rcode = pthread_create(&sw->pthread_id, &attr, fr_schedule_worker_thread, sw);
if (rcode != 0) {
+ MPRINT("Failed to create worker %d: %s\n", i, strerror(errno));
talloc_free(sw);
break;
}
* Wait for all of the workers to start.
*/
for (i = 0; i < num_workers; i++) {
+ MPRINT("Waiting for semaphore from worker %d/%d\n", i, num_workers);
SEM_WAIT_INTR(&sc->semaphore);
}
int num_workers_exited = sc->num_workers_exited;
fr_schedule_worker_t *sw;
+ MPRINT("ERROR: Failed to create some workers\n");
+
PTHREAD_MUTEX_UNLOCK(&sc->mutex);
/*
* error(s).
*/
for (i = 0; i < num_workers_exited; i++) {
+ MPRINT("Pop exited %d/%d\n", i, num_workers_exited);
+
PTHREAD_MUTEX_LOCK(&sc->mutex);
sw = fr_heap_pop(sc->done_workers);
PTHREAD_MUTEX_UNLOCK(&sc->mutex);
* Tell the active workers to exit.
*/
for (i = 0; i < num_workers; i++) {
+ MPRINT("Signal to exit %d/%d\n", i, num_workers);
+
PTHREAD_MUTEX_LOCK(&sc->mutex);
sw = fr_heap_pop(sc->workers);
PTHREAD_MUTEX_UNLOCK(&sc->mutex);
* signaled us that they've exited.
*/
for (i = 0; i < num_workers; i++) {
+ MPRINT("Wait for semaphore indicating exit %d/%d\n", i, num_workers);
+
SEM_WAIT_INTR(&sc->semaphore);
}
}
#endif
+ MPRINT("Scheduler created successfully\n");
+
return sc;
}
fr_schedule_worker_t *sw;
sc->running = false;
+
#ifdef HAVE_PTHREAD_H
rad_assert(sc->num_workers > 0);
- // signal the network threads to exit
+ MPRINT("Destroying scheduler\n");
/*
* Signal the workers to exit. They will push themselves
* underneath the workers!
*/
for (i = 0; i < num; i++) {
+ MPRINT("Wait for semaphore indicating exit %d/%d\n", i, num);
SEM_WAIT_INTR(&sc->semaphore);
}