Пример #1
0
Master* master_new(Options* options) {
    utility_assert(options);

    /* Don't do anything in this function that will cause a log message. The
     * global engine is still NULL since we are creating it now, and logging
     * here will cause an assertion error.
     */

    Master* master = g_new0(Master, 1);
    MAGIC_INIT(master);

    master->options = options;
    master->random = random_new(options_getRandomSeed(options));

    gint minRunAhead = (SimulationTime)options_getMinRunAhead(options);
    master->minJumpTimeConfig = ((SimulationTime)minRunAhead) * SIMTIME_ONE_MILLISECOND;

    /* these are only avail in glib >= 2.30
     * setup signal handlers for gracefully handling shutdowns */
//  TODO
//  g_unix_signal_add(SIGTERM, (GSourceFunc)_master_handleInterruptSignal, master);
//  g_unix_signal_add(SIGHUP, (GSourceFunc)_master_handleInterruptSignal, master);
//  g_unix_signal_add(SIGINT, (GSourceFunc)_master_handleInterruptSignal, master);

    message("simulation master created");
    return master;
}
Пример #2
0
Master* master_new(Configuration* config) {
    MAGIC_ASSERT(config);

    /* Don't do anything in this function that will cause a log message. The
     * global engine is still NULL since we are creating it now, and logging
     * here will cause an assertion error.
     */

    Master* master = g_new0(Master, 1);
    MAGIC_INIT(master);

    master->config = config;
    master->random = random_new(config->randomSeed);
    master->runTimer = g_timer_new();

    master->minJumpTimeConfig = ((SimulationTime)config->minRunAhead) * SIMTIME_ONE_MILLISECOND;

    /* these are only avail in glib >= 2.30
     * setup signal handlers for gracefully handling shutdowns */
//	TODO
//	g_unix_signal_add(SIGTERM, (GSourceFunc)_master_handleInterruptSignal, master);
//	g_unix_signal_add(SIGHUP, (GSourceFunc)_master_handleInterruptSignal, master);
//	g_unix_signal_add(SIGINT, (GSourceFunc)_master_handleInterruptSignal, master);

    return master;
}
Пример #3
0
TEST(RandomClass, CreateXOrShiftObject)
{
	Random* pRandom;
	uint32_t nResult = 0;
	pRandom = random_new(setXorShiftSeed, nextXorShiftUInt32);
	POINTERS_EQUAL(setXorShiftSeed, pRandom->setSeed);
	POINTERS_EQUAL(nextXorShiftUInt32, pRandom->getNextUInt32);
}
Пример #4
0
Engine* engine_new(Configuration* config) {
	MAGIC_ASSERT(config);

	/* Don't do anything in this function that will cause a log message. The
	 * global engine is still NULL since we are creating it now, and logging
	 * here will cause an assertion error.
	 */

	Engine* engine = g_new0(Engine, 1);
	MAGIC_INIT(engine);

	engine->config = config;
	engine->random = random_new(config->randomSeed);
	engine->runTimer = g_timer_new();

	/* initialize the singleton-per-thread worker class */
	engine->workerKey.index = 0;
	engine->preloadKey.index = 0;

	/* holds all events if single-threaded, and non-node events otherwise. */
	engine->masterEventQueue =
			asyncpriorityqueue_new((GCompareDataFunc)shadowevent_compare, NULL,
			(GDestroyNotify)shadowevent_free);
	engine->workersIdle = g_cond_new();
	engine->engineIdle = g_mutex_new();

	engine->registry = registry_new();
	registry_register(engine->registry, SOFTWARE, NULL, software_free);
	registry_register(engine->registry, CDFS, NULL, cdf_free);
	registry_register(engine->registry, PLUGINPATHS, g_free, g_free);

	engine->minTimeJump = config->minRunAhead * SIMTIME_ONE_MILLISECOND;

	engine->internet = internetwork_new();

	engine->lock = g_mutex_new();

	/* get the raw speed of the experiment machine */
	gchar* contents = NULL;
	gsize length = 0;
	GError* error = NULL;
	if(!g_file_get_contents(CONFIG_CPU_MAX_FREQ_FILE, &contents, &length, &error)) {
		engine->rawFrequencyKHz = 0;
	} else {
		engine->rawFrequencyKHz = (guint)atoi(contents);
	}

	return engine;
}
Пример #5
0
void test_seeding(unsigned int num)
{
    struct random *p1, *p2;
    unsigned int seed[] = { 1, 2, 3, 4 };
    int err;
    
    p1 = random_new();
    p2 = random_new();
    
    assert(p1);
    assert(p2);
    
    err = random_set_seed(p1, seed, ARRAY_SIZE(seed));
    assert(err == 0);
    
    err = random_set_seed(p2, seed, ARRAY_SIZE(seed));
    assert(err == 0);
    
    while(num--)
        assert(random_uint(p1) == random_uint(p2));
    
    random_delete(p1);
    random_delete(p2);
}
Пример #6
0
/* Initialize new World */
struct World * world_new(uint32_t seed){
    struct World * self;
    struct Random * random;
    
    if (!size){
        size = mm_new(sizeof(struct World));
    }
    
    if ((self = mm_alloc(size))){
        self->seed = seed;
    	random = random_new(seed);
    	self->altitude = terrain_new(random_random(random));
    	self->climate = climate_new(random_random(random));
    	self->evil = climate_new(random_random(random));
    	random_del(random);
    }
    return self;
}
Пример #7
0
Slave* slave_new(Master* master, Configuration* config, guint randomSeed) {
    Slave* slave = g_new0(Slave, 1);
    MAGIC_INIT(slave);

    g_mutex_init(&(slave->lock));
    g_mutex_init(&(slave->pluginInitLock));

    slave->master = master;
    slave->config = config;
    slave->random = random_new(randomSeed);

    slave->rawFrequencyKHz = utility_getRawCPUFrequency(CONFIG_CPU_MAX_FREQ_FILE);
    if(slave->rawFrequencyKHz == 0) {
        info("unable to read '%s' for copying", CONFIG_CPU_MAX_FREQ_FILE);
    }

    slave->hosts = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
    slave->programs = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, (GDestroyNotify)program_free);

    slave->dns = dns_new();

    slave->nWorkers = (guint) configuration_getNWorkerThreads(config);
    slave->mainThreadWorker = worker_new(slave);

    slave->cwdPath = g_get_current_dir();
    slave->dataPath = g_build_filename(slave->cwdPath, "shadow.data", NULL);
    slave->hostsPath = g_build_filename(slave->dataPath, "hosts", NULL);

    if(g_file_test(slave->dataPath, G_FILE_TEST_EXISTS)) {
        gboolean success = utility_removeAll(slave->dataPath);
        utility_assert(success);
    }

    gchar* templateDataPath = g_build_filename(slave->cwdPath, "shadow.data.template", NULL);
    if(g_file_test(templateDataPath, G_FILE_TEST_EXISTS)) {
        gboolean success = utility_copyAll(templateDataPath, slave->dataPath);
        utility_assert(success);
    }
    g_free(templateDataPath);

    return slave;
}
Пример #8
0
void test_randomness(void)
{
    struct random *rand;
    unsigned int n, i, num;
    
    rand = random_new();
    assert(rand);
    
    num = 100;
    
    for(i = 0; i < num; ++i) {
        n = random_uint(rand);
        
        fprintf(stdout, "%-10u\t", n);
        
        if((i % 3) == 0)
            fprintf(stdout, "\n");
    }
    
    fprintf(stdout, "\n");
    
    random_delete(rand);
}
Пример #9
0
void test_duplicates(unsigned int num)
{
    const struct map_config map_conf = {
        .size           = MAP_DEFAULT_SIZE,
        .lower_bound    = MAP_DEFAULT_LOWER_BOUND,
        .upper_bound    = MAP_DEFAULT_UPPER_BOUND,
        .static_size    = false,
        .key_compare    = &compare_int,
        .key_hash       = &hash_uint,
        .data_delete    = NULL,
    };
    struct map *m;
    struct random *random;
    unsigned int i, n, dups1, dups2;;
    int err;
    
    m = map_new(&map_conf);
    random = random_new();
    
    assert(m);
    assert(random);
    
    dups1 = 0;
    
    for(i = 0; i < num; ++i) {
        n = random_uint(random);
        
        if(map_contains(m, (void *)(long) n)) {
            dups1 += 1;
        } else {
            err = map_insert(m, (void *)(long) n, (void *)(long) n);
            if(err < 0) {
                fprintf(stderr, "Warning: "
                        "Map unable to insert %u in %uth iteration: %s\n",
                        n, i, strerror(-err));
            }
        }
    }
    
    random_delete(random);
    map_clear(m);
    
    srand(time(NULL));
    
    dups2 = 0;
    
    for(i = 0; i < num; ++i) {
        n = rand();
        
        if(map_contains(m, (void *)(long) n)) {
            dups2 += 1;
        } else {
            err = map_insert(m, (void *)(long) n, (void *)(long) n);
            if(err < 0) {
                fprintf(stderr, "Warning: "
                "Map unable to insert %u in %uth iteration: %s\n",
                n, i, strerror(-err));
            }
        }
    }
    
    map_delete(m);
    
    fprintf(stdout,
            "random: After %u iterations there are %u (%lf %%) duplicates\n"
            "rand(): After %u iterations there are %u (%lf %%) duplicates\n", 
            num, dups1, (double) dups1 / num, num, dups2, (double) dups2 / num);
}

void test_range(unsigned int num)
{
    struct random *rand;
    unsigned int i, n;
    
    rand = random_new();
    assert(rand);
    
    for(i = 0; i < num; ++i) {
        n = random_uint_range(rand, 0, 100);
        assert(n <= 100);
        
        n = random_uint_range(rand, 1000, 10000);
        assert(n >= 1000 && n <= 10000);
        
        n = random_uint_range(rand, 99999, 123456);
        assert(n >= 99999 && n <= 123456);
        
        n = random_uint_range(rand, (unsigned int) 1e6 + 1, (unsigned int) 1e8);
        assert(n >= (unsigned int) 1e6 + 1 && n <= (unsigned int) 1e8);
        
        n = random_uint_range(rand, 0, 0);
        assert(n == 0);
        
        n = random_uint_range(rand, 100, 100);
        assert(n == 100);
    }
    
    random_delete(rand);
}

int main(int argc, char *argv[])
{
    unsigned int num;
    
    if(argc == 2)
        num = atoi(argv[1]);
    else
        num = 0;
    
    test_randomness();
    
    if(num) {
        test_seeding(num);
        test_duplicates(num);
        test_range(num);
    }
    
    fprintf(stdout, "Tests finished\n");
    
    return EXIT_SUCCESS;
}
Пример #10
0
JNIEXPORT void JNICALL Java_edu_wlu_cs_levy_breezyslam_algorithms_RMHCSLAM_init (JNIEnv *env, jobject thisobject, jint random_seed)
{
    ptr_to_obj(env, thisobject, random_new(random_seed));
}
Пример #11
0
Host* host_new(GQuark id, gchar* hostname, gchar* ipHint, gchar* geocodeHint, gchar* typeHint,
		guint64 requestedBWDownKiBps, guint64 requestedBWUpKiBps,
		guint cpuFrequency, gint cpuThreshold, gint cpuPrecision, guint nodeSeed,
		SimulationTime heartbeatInterval, GLogLevelFlags heartbeatLogLevel, gchar* heartbeatLogInfo,
		GLogLevelFlags logLevel, gboolean logPcap, gchar* pcapDir, gchar* qdisc,
		guint64 receiveBufferSize, gboolean autotuneReceiveBuffer,
		guint64 sendBufferSize, gboolean autotuneSendBuffer,
		guint64 interfaceReceiveLength) {
	Host* host = g_new0(Host, 1);
	MAGIC_INIT(host);

	host->id = id;
	host->name = g_strdup(hostname);
	host->random = random_new(nodeSeed);

	/* get unique virtual address identifiers for each network interface */
	Address* loopbackAddress = dns_register(worker_getDNS(), host->id, host->name, "127.0.0.1");
	Address* ethernetAddress = dns_register(worker_getDNS(), host->id, host->name, ipHint);

	/* connect to topology and get the default bandwidth */
	guint64 bwDownKiBps = 0, bwUpKiBps = 0;
	topology_attach(worker_getTopology(), ethernetAddress, host->random,
			ipHint, geocodeHint, typeHint, &bwDownKiBps, &bwUpKiBps);

	/* prefer assigned bandwidth if available */
	if(requestedBWDownKiBps) {
		bwDownKiBps = requestedBWDownKiBps;
	}
	if(requestedBWUpKiBps) {
		bwUpKiBps = requestedBWUpKiBps;
	}

	/* virtual addresses and interfaces for managing network I/O */
	NetworkInterface* loopback = networkinterface_new(loopbackAddress, G_MAXUINT32, G_MAXUINT32,
			logPcap, pcapDir, qdisc, interfaceReceiveLength);
	NetworkInterface* ethernet = networkinterface_new(ethernetAddress, bwDownKiBps, bwUpKiBps,
			logPcap, pcapDir, qdisc, interfaceReceiveLength);

	host->interfaces = g_hash_table_new_full(g_direct_hash, g_direct_equal,
			NULL, (GDestroyNotify) networkinterface_free);
	g_hash_table_replace(host->interfaces, GUINT_TO_POINTER((guint)networkinterface_getIPAddress(ethernet)), ethernet);
	g_hash_table_replace(host->interfaces, GUINT_TO_POINTER((guint)htonl(INADDR_LOOPBACK)), loopback);

	host->defaultInterface = ethernet;

	/* thread-level event communication with other nodes */
	g_mutex_init(&(host->lock));
	host->events = eventqueue_new();

	host->availableDescriptors = g_queue_new();
	host->descriptorHandleCounter = MIN_DESCRIPTOR;

	/* virtual descriptor management */
	host->descriptors = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, descriptor_unref);
	host->receiveBufferSize = receiveBufferSize;
	host->sendBufferSize = sendBufferSize;
	host->autotuneReceiveBuffer = autotuneReceiveBuffer;
	host->autotuneSendBuffer = autotuneSendBuffer;

	host->shadowToOSHandleMap = g_hash_table_new(g_direct_hash, g_direct_equal);
    host->osToShadowHandleMap = g_hash_table_new(g_direct_hash, g_direct_equal);
    host->unixPathToPortMap = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);

	/* applications this node will run */
	host->applications = g_queue_new();

	host->cpu = cpu_new(cpuFrequency, cpuThreshold, cpuPrecision);
	host->tracker = tracker_new(heartbeatInterval, heartbeatLogLevel, heartbeatLogInfo);
	host->logLevel = logLevel;
	host->logPcap = logPcap;
	host->pcapDir = pcapDir;

	message("Created Host '%s', ip %s, "

			"%"G_GUINT64_FORMAT" bwUpKiBps, %"G_GUINT64_FORMAT" bwDownKiBps, %"G_GUINT64_FORMAT" initSockSendBufSize, %"G_GUINT64_FORMAT" initSockRecvBufSize, "
			"%u cpuFrequency, %i cpuThreshold, %i cpuPrecision, %u seed",
			g_quark_to_string(host->id), networkinterface_getIPName(host->defaultInterface),
			bwUpKiBps, bwDownKiBps, sendBufferSize, receiveBufferSize,
			cpuFrequency, cpuThreshold, cpuPrecision, nodeSeed);

	return host;
}
Пример #12
0
/* Checks that the guessed balls in the state match up with the real balls
 * for all possible lasers (i.e. not just the ones that the player might
 * have already guessed). This is required because any layout with >4 balls
 * might have multiple valid solutions. Returns non-zero for a 'correct'
 * (i.e. consistent) layout. */
static int check_guesses(game_state *state, int cagey)
{
    game_state *solution, *guesses;
    int i, x, y, n, unused, tmp;
    int ret = 0;

    if (cagey) {
	/*
	 * First, check that each laser the player has already
	 * fired is consistent with the layout. If not, show them
	 * one error they've made and reveal no further
	 * information.
	 *
	 * Failing that, check to see whether the player would have
	 * been able to fire any laser which distinguished the real
	 * solution from their guess. If so, show them one such
	 * laser and reveal no further information.
	 */
	guesses = dup_game(state);
	/* clear out BALL_CORRECT on guess, make BALL_GUESS BALL_CORRECT. */
	for (x = 1; x <= state->w; x++) {
	    for (y = 1; y <= state->h; y++) {
		GRID(guesses, x, y) &= ~BALL_CORRECT;
		if (GRID(guesses, x, y) & BALL_GUESS)
		    GRID(guesses, x, y) |= BALL_CORRECT;
	    }
	}
	n = 0;
	for (i = 0; i < guesses->nlasers; i++) {
	    if (guesses->exits[i] != LASER_EMPTY &&
		guesses->exits[i] != laser_exit(guesses, i))
		n++;
	}
	if (n) {
	    /*
	     * At least one of the player's existing lasers
	     * contradicts their ball placement. Pick a random one,
	     * highlight it, and return.
	     *
	     * A temporary random state is created from the current
	     * grid, so that repeating the same marking will give
	     * the same answer instead of a different one.
	     */
	    random_state *rs = random_new((char *)guesses->grid,
					  (state->w+2)*(state->h+2) *
					  sizeof(unsigned int));
	    n = random_upto(rs, n);
	    random_free(rs);
	    for (i = 0; i < guesses->nlasers; i++) {
		if (guesses->exits[i] != LASER_EMPTY &&
		    guesses->exits[i] != laser_exit(guesses, i) &&
		    n-- == 0) {
		    state->exits[i] |= LASER_WRONG;
		    tmp = laser_exit(state, i);
		    if (RANGECHECK(state, tmp))
			state->exits[tmp] |= LASER_WRONG;
		    state->justwrong = TRUE;
		    free_game(guesses);
		    return 0;
		}
	    }
	}
	n = 0;
	for (i = 0; i < guesses->nlasers; i++) {
	    if (guesses->exits[i] == LASER_EMPTY &&
		laser_exit(state, i) != laser_exit(guesses, i))
		n++;
	}
	if (n) {
	    /*
	     * At least one of the player's unfired lasers would
	     * demonstrate their ball placement to be wrong. Pick a
	     * random one, highlight it, and return.
	     *
	     * A temporary random state is created from the current
	     * grid, so that repeating the same marking will give
	     * the same answer instead of a different one.
	     */
	    random_state *rs = random_new((char *)guesses->grid,
					  (state->w+2)*(state->h+2) *
					  sizeof(unsigned int));
	    n = random_upto(rs, n);
	    random_free(rs);
	    for (i = 0; i < guesses->nlasers; i++) {
		if (guesses->exits[i] == LASER_EMPTY &&
		    laser_exit(state, i) != laser_exit(guesses, i) &&
		    n-- == 0) {
		    fire_laser(state, i);
		    state->exits[i] |= LASER_OMITTED;
		    tmp = laser_exit(state, i);
		    if (RANGECHECK(state, tmp))
			state->exits[tmp] |= LASER_OMITTED;
		    state->justwrong = TRUE;
		    free_game(guesses);
		    return 0;
		}
	    }
	}
	free_game(guesses);
    }

    /* duplicate the state (to solution) */
    solution = dup_game(state);

    /* clear out the lasers of solution */
    for (i = 0; i < solution->nlasers; i++) {
        tmp = range2grid(solution, i, &x, &y, &unused);
        assert(tmp);
        GRID(solution, x, y) = 0;
        solution->exits[i] = LASER_EMPTY;
    }

    /* duplicate solution to guess. */
    guesses = dup_game(solution);

    /* clear out BALL_CORRECT on guess, make BALL_GUESS BALL_CORRECT. */
    for (x = 1; x <= state->w; x++) {
        for (y = 1; y <= state->h; y++) {
            GRID(guesses, x, y) &= ~BALL_CORRECT;
            if (GRID(guesses, x, y) & BALL_GUESS)
                GRID(guesses, x, y) |= BALL_CORRECT;
        }
    }

    /* for each laser (on both game_states), fire it if it hasn't been fired.
     * If one has been fired (or received a hit) and another hasn't, we know
     * the ball layouts didn't match and can short-circuit return. */
    for (i = 0; i < solution->nlasers; i++) {
        if (solution->exits[i] == LASER_EMPTY)
            fire_laser(solution, i);
        if (guesses->exits[i] == LASER_EMPTY)
            fire_laser(guesses, i);
    }

    /* check each game_state's laser against the other; if any differ, return 0 */
    ret = 1;
    for (i = 0; i < solution->nlasers; i++) {
        tmp = range2grid(solution, i, &x, &y, &unused);
        assert(tmp);

        if (solution->exits[i] != guesses->exits[i]) {
            /* If the original state didn't have this shot fired,
             * and it would be wrong between the guess and the solution,
             * add it. */
            if (state->exits[i] == LASER_EMPTY) {
                state->exits[i] = solution->exits[i];
                if (state->exits[i] == LASER_REFLECT ||
                    state->exits[i] == LASER_HIT)
                    GRID(state, x, y) = state->exits[i];
                else {
                    /* add a new shot, incrementing state's laser count. */
                    int ex, ey, newno = state->laserno++;
                    tmp = range2grid(state, state->exits[i], &ex, &ey, &unused);
                    assert(tmp);
                    GRID(state, x, y) = newno;
                    GRID(state, ex, ey) = newno;
                }
		state->exits[i] |= LASER_OMITTED;
            } else {
		state->exits[i] |= LASER_WRONG;
	    }
            ret = 0;
        }
    }
    if (ret == 0 ||
	state->nguesses < state->minballs ||
	state->nguesses > state->maxballs) goto done;

    /* fix up original state so the 'correct' balls end up matching the guesses,
     * as we've just proved that they were equivalent. */
    for (x = 1; x <= state->w; x++) {
        for (y = 1; y <= state->h; y++) {
            if (GRID(state, x, y) & BALL_GUESS)
                GRID(state, x, y) |= BALL_CORRECT;
            else
                GRID(state, x, y) &= ~BALL_CORRECT;
        }
    }

done:
    /* fill in nright and nwrong. */
    state->nright = state->nwrong = state->nmissed = 0;
    for (x = 1; x <= state->w; x++) {
        for (y = 1; y <= state->h; y++) {
            int bs = GRID(state, x, y) & (BALL_GUESS | BALL_CORRECT);
            if (bs == (BALL_GUESS | BALL_CORRECT))
                state->nright++;
            else if (bs == BALL_GUESS)
                state->nwrong++;
            else if (bs == BALL_CORRECT)
                state->nmissed++;
        }
    }
    free_game(solution);
    free_game(guesses);
    state->reveal = 1;
    return ret;
}
Пример #13
0
Scheduler* scheduler_new(SchedulerPolicyType policyType, guint nWorkers, gpointer threadUserData,
        guint schedulerSeed, SimulationTime endTime) {
    Scheduler* scheduler = g_new0(Scheduler, 1);
    MAGIC_INIT(scheduler);

    /* global lock */
    g_mutex_init(&(scheduler->globalLock));

    scheduler->startBarrier = countdownlatch_new(nWorkers+1);
    scheduler->finishBarrier = countdownlatch_new(nWorkers+1);
    scheduler->executeEventsBarrier = countdownlatch_new(nWorkers+1);
    scheduler->collectInfoBarrier = countdownlatch_new(nWorkers+1);
    scheduler->prepareRoundBarrier = countdownlatch_new(nWorkers+1);

    scheduler->endTime = endTime;
    scheduler->currentRound.endTime = scheduler->endTime;// default to one single round
    scheduler->currentRound.minNextEventTime = SIMTIME_MAX;

    scheduler->threadToWaitTimerMap = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)g_timer_destroy);
    scheduler->hostIDToHostMap = g_hash_table_new(g_direct_hash, g_direct_equal);

    scheduler->random = random_new(schedulerSeed);

    /* ensure we have sane default modes for the number of workers we are using */
    if(nWorkers == 0) {
        scheduler->policyType = SP_SERIAL_GLOBAL;
    } else if(nWorkers > 0 && policyType == SP_SERIAL_GLOBAL) {
        policyType = SP_PARALLEL_HOST_STEAL;
    } else {
        scheduler->policyType = policyType;
    }

    /* create the configured policy to handle queues */
    switch(scheduler->policyType) {
        case SP_PARALLEL_HOST_SINGLE: {
            scheduler->policy = schedulerpolicyhostsingle_new();
            break;
        }
        case SP_PARALLEL_HOST_STEAL: {
            scheduler->policy = schedulerpolicyhostsingle_new();
            break;
        }
        case SP_PARALLEL_THREAD_SINGLE: {
            scheduler->policy = schedulerpolicythreadsingle_new();
            break;
        }
        case SP_PARALLEL_THREAD_PERTHREAD: {
            scheduler->policy = schedulerpolicythreadperthread_new();
            break;
        }
        case SP_PARALLEL_THREAD_PERHOST: {
            scheduler->policy = schedulerpolicythreadperhost_new();
            break;
        }
        case SP_SERIAL_GLOBAL:
        default: {
            scheduler->policy = schedulerpolicyglobalsingle_new();
            break;
        }
    }
    utility_assert(scheduler->policy);

    /* make sure our ref count is set before starting the threads */
    scheduler->referenceCount = 1;

    scheduler->threadItems = g_queue_new();

    /* start up threads and create worker storage, each thread will call worker_new,
     * and wait at startBarrier until we are ready to launch */
    for(gint i = 0; i < nWorkers; i++) {
        GString* name = g_string_new(NULL);
        g_string_printf(name, "worker-%i", (i));

        SchedulerThreadItem* item = g_new0(SchedulerThreadItem, 1);
        item->notifyDoneRunning = countdownlatch_new(1);

        WorkerRunData* runData = g_new0(WorkerRunData, 1);
        runData->userData = threadUserData;
        runData->scheduler = scheduler;
        runData->threadID = i;
        runData->notifyDoneRunning = item->notifyDoneRunning;

        gint returnVal = pthread_create(&(item->thread), NULL, (void*(*)(void*))worker_run, runData);
        if(returnVal != 0) {
            critical("unable to create worker thread");
            return NULL;
        }

        returnVal = pthread_setname_np(item->thread, name->str);
        if(returnVal != 0) {
            warning("unable to set name of worker thread to '%s'", name->str);
        }
        utility_assert(item->thread);

        g_queue_push_tail(scheduler->threadItems, item);
        logger_register(logger_getDefault(), item->thread);

        g_string_free(name, TRUE);
    }
    message("main scheduler thread will operate with %u worker threads", nWorkers);

    return scheduler;
}