/*
 * Create a new thread based on an existing one.
 *
 * The new thread has name NAME, and starts executing in function
 * ENTRYPOINT. DATA1 and DATA2 are passed to ENTRYPOINT.
 *
 * The new thread is created in the process P. If P is null, the
 * process is inherited from the caller. It will start on the same CPU
 * as the caller, unless the scheduler intervenes first.
 */
int
thread_fork(const char *name,
            struct proc *proc,
            void (*entrypoint)(void *data1, unsigned long data2),
            void *data1, unsigned long data2)
{
    struct thread *newthread;
    int result;

    newthread = thread_create(name);
    if (newthread == NULL) {
        return ENOMEM;
    }

    /* Allocate a stack */
    newthread->t_stack = kmalloc(STACK_SIZE);
    if (newthread->t_stack == NULL) {
        thread_destroy(newthread);
        return ENOMEM;
    }
    thread_checkstack_init(newthread);

    /*
     * Now we clone various fields from the parent thread.
     */

    /* Thread subsystem fields */
    newthread->t_cpu = curthread->t_cpu;

    /* Attach the new thread to its process */
    if (proc == NULL) {
        proc = curthread->t_proc;
    }
    result = proc_addthread(proc, newthread);
    if (result) {
        /* thread_destroy will clean up the stack */
        thread_destroy(newthread);
        return result;
    }

    /*
     * Because new threads come out holding the cpu runqueue lock
     * (see notes at bottom of thread_switch), we need to account
     * for the spllower() that will be done releasing it.
     */
    newthread->t_iplhigh_count++;

    spinlock_acquire(&thread_count_lock);
    ++thread_count;
    wchan_wakeall(thread_count_wchan, &thread_count_lock);
    spinlock_release(&thread_count_lock);

    /* Set up the switchframe so entrypoint() gets called */
    switchframe_init(newthread, entrypoint, data1, data2);

    /* Lock the current cpu's run queue and make the new thread runnable */
    thread_make_runnable(newthread, false);

    return 0;
}
Beispiel #2
0
/*
 * Create a CPU structure. This is used for the bootup CPU and
 * also for secondary CPUs.
 *
 * The hardware number (the number assigned by firmware or system
 * board config or whatnot) is tracked separately because it is not
 * necessarily anything sane or meaningful.
 */
struct cpu *
cpu_create(unsigned hardware_number)
{
	struct cpu *c;
	int result;
	char namebuf[16];

	c = kmalloc(sizeof(*c));
	if (c == NULL) {
		panic("cpu_create: Out of memory\n");
	}

	c->c_self = c;
	c->c_hardware_number = hardware_number;

	c->c_curthread = NULL;
	threadlist_init(&c->c_zombies);
	c->c_hardclocks = 0;
	c->c_spinlocks = 0;

	c->c_isidle = false;
	threadlist_init(&c->c_runqueue);
	spinlock_init(&c->c_runqueue_lock);

	c->c_ipi_pending = 0;
	c->c_numshootdown = 0;
	spinlock_init(&c->c_ipi_lock);

	result = cpuarray_add(&allcpus, c, &c->c_number);
	if (result != 0) {
		panic("cpu_create: array_add: %s\n", strerror(result));
	}

	snprintf(namebuf, sizeof(namebuf), "<boot #%d>", c->c_number);
	c->c_curthread = thread_create(namebuf);
	if (c->c_curthread == NULL) {
		panic("cpu_create: thread_create failed\n");
	}
	result = proc_addthread(kproc, c->c_curthread);
	if (result) {
		panic("cpu_create: proc_addthread:: %s\n", strerror(result));
	}

	if (c->c_number == 0) {
		/*
		 * Leave c->c_curthread->t_stack NULL for the boot
		 * cpu. This means we're using the boot stack, which
		 * can't be freed. (Exercise: what would it take to
		 * make it possible to free the boot stack?)
		 */
		/*c->c_curthread->t_stack = ... */
	}
	else {
		c->c_curthread->t_stack = kmalloc(STACK_SIZE);
		if (c->c_curthread->t_stack == NULL) {
			panic("cpu_create: couldn't allocate stack");
		}
		thread_checkstack_init(c->c_curthread);
	}
	c->c_curthread->t_cpu = c;

	cpu_machdep_init(c);

	return c;
}
/*
 * Create a CPU structure. This is used for the bootup CPU and
 * also for secondary CPUs.
 *
 * The hardware number (the number assigned by firmware or system
 * board config or whatnot) is tracked separately because it is not
 * necessarily anything sane or meaningful.
 */
struct cpu *
cpu_create(unsigned hardware_number)
{
    struct cpu *c;
    int result;
    char namebuf[16];

    c = kmalloc(sizeof(*c));
    if (c == NULL) {
        panic("cpu_create: Out of memory\n");
    }

    c->c_self = c;
    c->c_hardware_number = hardware_number;

    c->c_curthread = NULL;
    threadlist_init(&c->c_zombies);
    c->c_hardclocks = 0;
    c->c_spinlocks = 0;

    c->c_isidle = false;
    threadlist_init(&c->c_runqueue);
    spinlock_init(&c->c_runqueue_lock);

    c->c_ipi_pending = 0;
    c->c_numshootdown = 0;
    spinlock_init(&c->c_ipi_lock);

    result = cpuarray_add(&allcpus, c, &c->c_number);
    if (result != 0) {
        panic("cpu_create: array_add: %s\n", strerror(result));
    }

    snprintf(namebuf, sizeof(namebuf), "<boot #%d>", c->c_number);
    c->c_curthread = thread_create(namebuf);
    if (c->c_curthread == NULL) {
        panic("cpu_create: thread_create failed\n");
    }
    c->c_curthread->t_cpu = c;

    if (c->c_number == 0) {
        /*
         * Leave c->c_curthread->t_stack NULL for the boot
         * cpu. This means we're using the boot stack, which
         * can't be freed. (Exercise: what would it take to
         * make it possible to free the boot stack?)
         */
        /*c->c_curthread->t_stack = ... */
    }
    else {
        c->c_curthread->t_stack = kmalloc(STACK_SIZE);
        if (c->c_curthread->t_stack == NULL) {
            panic("cpu_create: couldn't allocate stack");
        }
        thread_checkstack_init(c->c_curthread);
    }

    /*
     * If there is no curcpu (or curthread) yet, we are creating
     * the first (boot) cpu. Initialize curcpu and curthread as
     * early as possible so that other code can take locks without
     * exploding.
     */
    if (!CURCPU_EXISTS()) {
        /*
         * Initializing curcpu and curthread is
         * machine-dependent because either of curcpu and
         * curthread might be defined in terms of the other.
         */
        INIT_CURCPU(c, c->c_curthread);

        /*
         * Now make sure both t_cpu and c_curthread are
         * set. This might be partially redundant with
         * INIT_CURCPU depending on how things are defined.
         */
        curthread->t_cpu = curcpu;
        curcpu->c_curthread = curthread;
    }

    result = proc_addthread(kproc, c->c_curthread);
    if (result) {
        panic("cpu_create: proc_addthread:: %s\n", strerror(result));
    }

    cpu_machdep_init(c);

    return c;
}