Beispiel #1
0
/** Thread used to bring up userspace thread.
 *
 * @param arg Pointer to structure containing userspace entry and stack
 *     addresses.
 */
void uinit(void *arg)
{
	/*
	 * So far, we don't have a use for joining userspace threads so we
	 * immediately detach each uinit thread. If joining of userspace threads
	 * is required, some userspace API based on the kernel mechanism will
	 * have to be implemented. Moreover, garbage collecting of threads that
	 * didn't detach themselves and nobody else joined them will have to be
	 * deployed for the event of forceful task termination.
	 */
	thread_detach(THREAD);
	
#ifdef CONFIG_UDEBUG
	udebug_stoppable_end();
#endif
	
	uspace_arg_t *uarg = (uspace_arg_t *) arg;
	uspace_arg_t local_uarg;
	
	local_uarg.uspace_entry = uarg->uspace_entry;
	local_uarg.uspace_stack = uarg->uspace_stack;
	local_uarg.uspace_stack_size = uarg->uspace_stack_size;
	local_uarg.uspace_uarg = uarg->uspace_uarg;
	local_uarg.uspace_thread_function = NULL;
	local_uarg.uspace_thread_arg = NULL;
	
	free(uarg);
	
	userspace(&local_uarg);
}
Beispiel #2
0
void CFetcher::QueueAdd(CFetchTask *pTask, const char *pUrl, const char *pDest, int StorageType, void *pUser, COMPFUNC pfnCompCb, PROGFUNC pfnProgCb)
{
	str_copy(pTask->m_aUrl, pUrl, sizeof(pTask->m_aUrl));
	str_copy(pTask->m_aDest, pDest, sizeof(pTask->m_aDest));
	pTask->m_StorageType = StorageType;
	pTask->m_pfnProgressCallback = pfnProgCb;
	pTask->m_pfnCompCallback = pfnCompCb;
	pTask->m_pUser = pUser;
	pTask->m_Size = pTask->m_Progress = 0;
	pTask->m_Abort = false;

	lock_wait(m_Lock);
	if(!m_pThHandle)
	{
		m_pThHandle = thread_init(&FetcherThread, this);
		thread_detach(m_pThHandle);
	}

	if(!m_pFirst)
	{
		m_pFirst = pTask;
		m_pLast = m_pFirst;
	}
	else
	{
		m_pLast->m_pNext = pTask;
		m_pLast = pTask;
	}
	pTask->m_State = CFetchTask::STATE_QUEUED;
	lock_unlock(m_Lock);
}
void CSqlJob::Start(bool ReadOnly)
{
	m_ReadOnly = ReadOnly;
	
	void *registerThread = thread_init(CSqlJob::Exec, this);
	thread_detach(registerThread);
}
Beispiel #4
0
/** Work-stealing loop for workers */
static int worker_run (void * data) {
    struct worker_args * args = (struct worker_args*) data;
    int id = args->id;

    errval_t err = thread_detach(thread_self());
    assert(err_is_ok(err));

    free(args);
    workers[id].worker_thr = thread_self();
    workers[id].id = id;
    workers[id].core_id = disp_get_core_id();

    struct generic_task_desc * _tweed_top_ = NULL;
    
    thread_set_tls( &(workers[id]));

    trace_init_disp();

    num_dispatchers += 1;

    // start trying to steal work
    int steal_id = (id+1) % num_workers;
    while(!do_quit) {
        int success = steal(_tweed_top_, &workers[steal_id]);
        if (!success) {
            // try next worker
            steal_id = (steal_id+1) % num_workers;
        }
    }
    exit(0);
    return 0;
}
Beispiel #5
0
struct thread *thread_create(unsigned int flags, void *(*run)(void *), void *arg) {
	struct thread *t;
	int priority;

	/* check mutually exclusive flags */
	if ((flags & THREAD_FLAG_PRIORITY_LOWER)
			&& (flags & THREAD_FLAG_PRIORITY_HIGHER)) {
		return err_ptr(EINVAL);
	}

	if((flags & THREAD_FLAG_NOTASK) && !(flags & THREAD_FLAG_SUSPENDED)) {
		return err_ptr(EINVAL);
	}

	/* check correct executive function */
	if (!run) {
		return err_ptr(EINVAL);
	}

	/* calculate current thread priority. It can be change later with
	 * thread_set_priority () function
	 */
	priority = thread_priority_by_flags(flags);

	/* below we will work with thread's instances and therefore we need to
	 * lock scheduler (disable scheduling) to our structures is not be
	 * corrupted
	 */
	sched_lock();
	{
		/* allocate memory */
		if (!(t = thread_alloc())) {
			t = err_ptr(ENOMEM);
			goto out_unlock;
		}

		/* initialize internal thread structure */
		thread_init(t, priority, run, arg);

		/* link with task if needed */
		if (!(flags & THREAD_FLAG_NOTASK)) {
			task_thread_register(task_self(), t);
		}

		thread_cancel_init(t);

		if (!(flags & THREAD_FLAG_SUSPENDED)) {
			thread_launch(t);
		}

		if (flags & THREAD_FLAG_DETACHED) {
			thread_detach(t);
		}

	}
out_unlock:
	sched_unlock();

	return t;
}
Beispiel #6
0
/**
 * @brief Create a new Othello User Interface.
 *
 * Allocate event resources & launch user-input event thread.
 *
 */
void ui_event_init(UI *ui)
{
	event_init(ui->event);
	
	thread_create(&ui->event->thread, ui_read_input_loop, ui);
	thread_detach(ui->event->thread);
}
Beispiel #7
0
void thread_create(thread_t *thread)
{
#ifdef ACE_WINDOWS
	thread->thread = (HANDLE)-1;
	_ReadWriteBarrier();
	
	thread->thread = (HANDLE)_beginthreadex(NULL, 0,
		&internal_win32_callback_wrapper, NULL, 0, &thread->thread_id);
#else
	pthread_attr_init(&thread->thread_attr);
	if (thread->flags & ACE_THREAD_JOINABLE) {
		pthread_attr_setdetachstate(&thread->thread_attr,
			PTHREAD_CREATE_JOINABLE);
	}
	
	if (pthread_create(&thread->thread, &thread->thread_attr,
		&internal_linux_callback_wrapper, (void *)thread)) {
		
		exit(ENOMEM);
	}
	
	pthread_attr_destroy(&thread->thread_attr);
#endif

	if (thread->flags & ACE_THREAD_DETACHED) {
		thread_detach(thread);
	}
}
Beispiel #8
0
static int join_tester_server(void *arg)
{
	int ret;
	status_t err;
	thread_t *t;

	printf("\ttesting thread_join/thread_detach\n");

	printf("\tcreating and waiting on thread to exit with thread_join\n");
	t = thread_create("join tester", &join_tester, (void *)1, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
	thread_resume(t);
	ret = 99;
	printf("\tthread magic is 0x%x (should be 0x%x)\n", t->magic, THREAD_MAGIC);
	err = thread_join(t, &ret, INFINITE_TIME);
	printf("\tthread_join returns err %d, retval %d\n", err, ret);
	printf("\tthread magic is 0x%x (should be 0)\n", t->magic);

	printf("\tcreating and waiting on thread to exit with thread_join, after thread has exited\n");
	t = thread_create("join tester", &join_tester, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
	thread_resume(t);
	thread_sleep(1000); // wait until thread is already dead
	ret = 99;
	printf("\tthread magic is 0x%x (should be 0x%x)\n", t->magic, THREAD_MAGIC);
	err = thread_join(t, &ret, INFINITE_TIME);
	printf("\tthread_join returns err %d, retval %d\n", err, ret);
	printf("\tthread magic is 0x%x (should be 0)\n", t->magic);

	printf("\tcreating a thread, detaching it, let it exit on its own\n");
	t = thread_create("join tester", &join_tester, (void *)3, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
	thread_detach(t);
	thread_resume(t);
	thread_sleep(1000); // wait until the thread should be dead
	printf("\tthread magic is 0x%x (should be 0)\n", t->magic);

	printf("\tcreating a thread, detaching it after it should be dead\n");
	t = thread_create("join tester", &join_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
	thread_resume(t);
	thread_sleep(1000); // wait until thread is already dead
	printf("\tthread magic is 0x%x (should be 0x%x)\n", t->magic, THREAD_MAGIC);
	thread_detach(t);
	printf("\tthread magic is 0x%x\n", t->magic);

	printf("\texiting join tester server\n");

	return 55;
}
Beispiel #9
0
void CServerBrowser::LoadCache()
{
	if(m_ServerdataLocked)
		return;
	m_ServerdataLocked = true;
	void *pThread = thread_init(LoadCacheThread, this);
	thread_detach(pThread);
}
Beispiel #10
0
void CGraphics_OpenGL::ScreenshotDirect(const char *pFilename)
{
	// fetch image data
	int y;
	int w = m_ScreenWidth;
	int h = m_ScreenHeight;
	unsigned char *pPixelData = (unsigned char *)mem_alloc(w*(h+1)*3, 1);
	unsigned char *pTempRow = pPixelData+w*h*3;
	GLint Alignment;
	glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment);
	glPixelStorei(GL_PACK_ALIGNMENT, 1);
	glReadPixels(0,0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pPixelData);
	glPixelStorei(GL_PACK_ALIGNMENT, Alignment);

	if (g_Config.m_ClScreenShotThread)
	{
        ScreenshotThreadStruct *ScreenshotData = new ScreenshotThreadStruct();
        str_copy(ScreenshotData->m_aFilename, pFilename, sizeof(ScreenshotData->m_aFilename));
        ScreenshotData->m_h = h;
        ScreenshotData->m_w = w;
        ScreenshotData->m_pPixelData = pPixelData;
        ScreenshotData->m_pSelf = this;
        void *t = thread_create(ScreenShotThread, ScreenshotData);
        thread_detach(t);
	}
	else
	{
        // flip the pixel because opengl works from bottom left corner
        for(y = 0; y < h/2; y++)
        {
            mem_copy(pTempRow, pPixelData+y*w*3, w*3);
            mem_copy(pPixelData+y*w*3, pPixelData+(h-y-1)*w*3, w*3);
            mem_copy(pPixelData+(h-y-1)*w*3, pTempRow,w*3);
        }

        // find filename
        {
            char aWholePath[1024];
            png_t Png; // ignore_convention

            IOHANDLE File  = m_pStorage->OpenFile(pFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE, aWholePath, sizeof(aWholePath));
            if(File)
                io_close(File);

            // save png
            char aBuf[256];
            str_format(aBuf, sizeof(aBuf), "saved screenshot to '%s'", aWholePath);
            m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf);
            png_open_file_write(&Png, aWholePath); // ignore_convention
            png_set_data(&Png, w, h, 8, PNG_TRUECOLOR, (unsigned char *)pPixelData); // ignore_convention
            png_close_file(&Png); // ignore_convention
        }

        // clean up
        mem_free(pPixelData);
	}
}
Beispiel #11
0
Datei: app.c Projekt: DSKIM3/lk
static void start_app(const struct app_descriptor *app)
{
	uint32_t stack_size = (app->flags & APP_FLAG_CUSTOM_STACK_SIZE) ? app->stack_size : DEFAULT_STACK_SIZE;

	printf("starting app %s\n", app->name);
	thread_t *t = thread_create(app->name, &app_thread_entry, (void *)app, DEFAULT_PRIORITY, stack_size);
	thread_detach(t);
	thread_resume(t);
}
Beispiel #12
0
void lk_main(void)
{
	inc_critical_section();

	// get us into some sort of thread context
	thread_init_early();

	// early arch stuff
	lk_init_level(LK_INIT_LEVEL_ARCH_EARLY - 1);
	arch_early_init();

	// do any super early platform initialization
	lk_init_level(LK_INIT_LEVEL_PLATFORM_EARLY - 1);
	platform_early_init();

	// do any super early target initialization
	lk_init_level(LK_INIT_LEVEL_TARGET_EARLY - 1);
	target_early_init();

	dprintf(INFO, "welcome to lk\n\n");
#if WITH_PLATFORM_MSM_SHARED
	bs_set_timestamp(BS_BL_START);
#endif

	// deal with any static constructors
	dprintf(SPEW, "calling constructors\n");
	call_constructors();

	// bring up the kernel heap
	dprintf(SPEW, "initializing heap\n");
	lk_init_level(LK_INIT_LEVEL_HEAP - 1);
	heap_init();

#if WITH_PLATFORM_MSM_SHARED
	__stack_chk_guard_setup();
#endif

	// initialize the kernel
	lk_init_level(LK_INIT_LEVEL_KERNEL - 1);
	kernel_init();

	lk_init_level(LK_INIT_LEVEL_THREADING - 1);

#if (!ENABLE_NANDWRITE)
	// create a thread to complete system initialization
	dprintf(SPEW, "creating bootstrap completion thread\n");
	thread_t *t = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
	thread_detach(t);
	thread_resume(t);

	// become the idle thread and enable interrupts to start the scheduler
	thread_become_idle();
#else
	bootstrap_nandwrite();
#endif
}
Beispiel #13
0
/* called from arch code */
void lk_main(ulong arg0, ulong arg1, ulong arg2, ulong arg3)
{
	// save the boot args
	lk_boot_args[0] = arg0;
	lk_boot_args[1] = arg1;
	lk_boot_args[2] = arg2;
	lk_boot_args[3] = arg3;

	// get us into some sort of thread context
	thread_init_early();

	// early arch stuff
	lk_primary_cpu_init_level(LK_INIT_LEVEL_EARLIEST, LK_INIT_LEVEL_ARCH_EARLY - 1);
	arch_early_init();

	// do any super early platform initialization
	lk_primary_cpu_init_level(LK_INIT_LEVEL_ARCH_EARLY, LK_INIT_LEVEL_PLATFORM_EARLY - 1);
	platform_early_init();

	// do any super early target initialization
	lk_primary_cpu_init_level(LK_INIT_LEVEL_PLATFORM_EARLY, LK_INIT_LEVEL_TARGET_EARLY - 1);
	target_early_init();

#if WITH_SMP
	dprintf(INFO, "\nwelcome to lk/MP\n\n");
#else
	dprintf(INFO, "\nwelcome to lk\n\n");
#endif
	dprintf(INFO, "boot args 0x%lx 0x%lx 0x%lx 0x%lx\n",
		lk_boot_args[0], lk_boot_args[1], lk_boot_args[2], lk_boot_args[3]);

	// deal with any static constructors
	dprintf(SPEW, "calling constructors\n");
	call_constructors();

	// bring up the kernel heap
	dprintf(SPEW, "initializing heap\n");
	lk_primary_cpu_init_level(LK_INIT_LEVEL_TARGET_EARLY, LK_INIT_LEVEL_HEAP - 1);
	heap_init();

	// initialize the kernel
	lk_primary_cpu_init_level(LK_INIT_LEVEL_HEAP, LK_INIT_LEVEL_KERNEL - 1);
	kernel_init();

	lk_primary_cpu_init_level(LK_INIT_LEVEL_KERNEL, LK_INIT_LEVEL_THREADING - 1);

	// create a thread to complete system initialization
	dprintf(SPEW, "creating bootstrap completion thread\n");
	thread_t *t = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
	t->pinned_cpu = 0;
	thread_detach(t);
	thread_resume(t);

	// become the idle thread and enable interrupts to start the scheduler
	thread_become_idle();
}
void ThreadedSocketAcceptor::removeThread( int s )
{
  Locker l(m_mutex);
  SocketToThread::iterator i = m_threads.find( s );
  if ( i != m_threads.end() )
  {
    thread_detach( i->second );
    m_threads.erase( i );
  }
}
Beispiel #15
0
static void producer(void *arg)
{
	thread_detach(THREAD);
	
	waitq_sleep(&can_start);
	
	semaphore_down(&sem);
	atomic_inc(&items_produced);
	thread_usleep(250);
	semaphore_up(&sem);
}
Beispiel #16
0
static int span_slave_thread(void *arg)
{
    errval_t err = thread_detach(thread_self());
    assert(err_is_ok(err));

    for(;;) {
        event_dispatch(get_default_waitset());
    }

    return 0;
}
Beispiel #17
0
static void consumer(void *arg)
{
	thread_detach(THREAD);
	
	waitq_sleep(&can_start);
	
	semaphore_down(&sem);
	atomic_inc(&items_consumed);
	thread_usleep(500);
	semaphore_up(&sem);
}
void ThreadedSSLSocketInitiator::removeThread(SocketKey s)
{
  Locker l(m_mutex);
  SocketToThread::iterator i = m_threads.find(s);

  if (i != m_threads.end())
  {
    thread_detach(i->second);
    if (i->first.second != 0)
      SSL_free(i->first.second);
    m_threads.erase(i);
  }
}
Beispiel #19
0
int svc_init_audio(unsigned int rate, unsigned int frame_size) {
    input_audio_data = svc_audio_data_create(frame_size);
    output_audio_data = svc_audio_data_create(frame_size);

    oss_open(rate);

    fs = frame_size;
    running = 1;
    thread_create(&rt, reader, NULL);
    thread_detach(rt);
    assert(rt > 0);

    return 0;
}
Beispiel #20
0
BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
{
    switch(fdwReason) {
    case DLL_PROCESS_ATTACH:
        hInst = hInstDLL;
        break;
    case DLL_PROCESS_DETACH:
        process_detach();
        break;
    case DLL_THREAD_DETACH:
        thread_detach();
        break;
    }
    return TRUE;
}
Beispiel #21
0
/***********************************************************************
 *              DllMain
 */
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved)
{
    BOOL ret = TRUE;

    switch(reason)
    {
    case DLL_PROCESS_ATTACH:
        ret = process_attach();
        break;
    case DLL_THREAD_DETACH:
        thread_detach();
        break;
    }
    return ret;
}
Beispiel #22
0
FifoConsole::FifoConsole(IConsole *pConsole, char *pFifoFile, int flag)
{
	m_pFifoFile = pFifoFile;
	if(m_pFifoFile[0] == '\0')
		return;

	gs_stopFifoThread = false;
	if(gs_FifoLock == 0)
		gs_FifoLock = lock_create();

	m_pFifoThread = thread_init(ListenFifoThread, this);
	m_pConsole = pConsole;
	m_flag = flag;

	thread_detach(m_pFifoThread);
}
Beispiel #23
0
/**************************************************************************
 *		DllMain
 */
BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
{
    switch(reason)
    {
    case DLL_PROCESS_ATTACH:
        LoadLibrary16( "krnl386.exe" );
        /* fall through */
    case DLL_THREAD_ATTACH:
        thread_attach();
        break;
    case DLL_THREAD_DETACH:
        thread_detach();
        break;
    }
    return TRUE;
}
Beispiel #24
0
int main() {
    thread_t *th[N];
    int i;
    void *ret;

    for(i=0; i<N; i++) {
	th[i] = thread_new(thfunc, (void*)(intptr_t)i);
    }

    for(i=0; i<N; i++) {
	thread_join(th[i], &ret);
	printf("joined thread i=%d ret=%p\n", i, ret);
	thread_detach(th[i]);
    }

    return 0;
}
Beispiel #25
0
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
{
    struct sys_thread *st = malloc(sizeof(struct sys_thread));
    DEBUG_ASSERT(st);

    thread_t *t = thread_create(name, sys_thread_func, st, prio, stacksize);
    DEBUG_ASSERT(t);

    st->t = t;
    st->func = thread;
    st->arg = arg;

    thread_detach(t);
    thread_resume(t);

    return st;
}
Beispiel #26
0
/***********************************************************************
 *           UserClientDllInitialize  (USER32.@)
 *
 * USER dll initialisation routine (exported as UserClientDllInitialize for compatibility).
 */
BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
{
    BOOL ret = TRUE;
    switch(reason)
    {
    case DLL_PROCESS_ATTACH:
        user32_module = inst;
        ret = process_attach();
        break;
    case DLL_THREAD_DETACH:
        thread_detach();
        break;
    case DLL_PROCESS_DETACH:
        USER_unload_driver();
        break;
    }
    return ret;
}
Beispiel #27
0
void lk_init_secondary_cpus(uint secondary_cpu_count)
{
	if (secondary_cpu_count >= SMP_MAX_CPUS) {
		dprintf(CRITICAL, "Invalid secondary_cpu_count %d, SMP_MAX_CPUS %d\n",
			secondary_cpu_count, SMP_MAX_CPUS);
		secondary_cpu_count = SMP_MAX_CPUS - 1;
	}
	for (uint i = 0; i < secondary_cpu_count; i++) {
		dprintf(SPEW, "creating bootstrap completion thread for cpu %d\n", i + 1);
		thread_t *t = thread_create("secondarybootstrap2",
					    &secondary_cpu_bootstrap2, NULL,
					    DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
		t->pinned_cpu = i + 1;
		thread_detach(t);
		secondary_bootstrap_threads[i] = t;
	}
	secondary_bootstrap_thread_count = secondary_cpu_count;
}
Beispiel #28
0
void lk_main(void)
{
	inc_critical_section();

	// get us into some sort of thread context
	thread_init_early();

	// early arch stuff
	arch_early_init();

	// do any super early platform initialization
	platform_early_init();

	// do any super early target initialization
	target_early_init();

	dprintf(INFO, "welcome to lk\n\n");

	// deal with any static constructors
	dprintf(SPEW, "calling constructors\n");
	call_constructors();

	// bring up the kernel heap
	dprintf(SPEW, "initializing heap\n");
	heap_init();

	// initialize the kernel
	kernel_init();

	// create a thread to complete system initialization
	dprintf(SPEW, "creating bootstrap completion thread\n");
	thread_t *t = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
	thread_detach(t);
	thread_resume(t);

	// become the idle thread and enable interrupts to start the scheduler
	thread_become_idle();
}
Beispiel #29
0
/*
 * nk_join
 *
 * join (wait) on the given thread
 *
 * t: the thread to wait on
 * retval: where the waited-on thread should 
 *         put its output
 *
 * returns  -EINVAL on error, 0 on success
 *
 */
int
nk_join (nk_thread_id_t t, void ** retval)
#ifndef NAUT_CONFIG_USE_RT_SCHEDULER
{
    nk_thread_t *thethread = (nk_thread_t*)t;
    uint8_t flags;

    ASSERT(thethread->parent == get_cur_thread());

    flags = irq_disable_save();

    while (__sync_lock_test_and_set(&thethread->lock, 1));

    if (thethread->status == NK_THR_EXITED) {
        if (thethread->output) {
            *retval = thethread->output;
        }
        goto out;
    } else {
        while (*(volatile int*)&thethread->status != NK_THR_EXITED) {
            __sync_lock_release(&thethread->lock);
            cli();
            nk_wait(t);
            sti();
            while (__sync_lock_test_and_set(&thethread->lock, 1));
        }
    }

    if (retval) {
        *retval = thethread->output;
    }

out:
    __sync_lock_release(&thethread->lock);
    thread_detach(thethread);
    irq_enable_restore(flags);
    return 0;
}
Beispiel #30
0
/*
 * Create a new thread based on an existing one.
 * The new thread has name NAME, and starts executing in function FUNC.
 * DATA1 and DATA2 are passed to FUNC.
 */
int
thread_fork(const char *name, 
	    void *data1, unsigned long data2,
	    void (*func)(void *, unsigned long),
	    pid_t *ret)
{
	struct thread *newguy;
	int s, result;

	/* Allocate a thread */
	newguy = thread_create(name);
	if (newguy==NULL) {
		return ENOMEM;
	}

	/* ASST1: Allocate a pid */
	result = pid_alloc(&newguy->t_pid);
	if (result != 0) {
	  kfree(newguy->t_name);
	  kfree(newguy);
	  return result;
	}

	/* Allocate a stack */
	newguy->t_stack = kmalloc(STACK_SIZE);
	if (newguy->t_stack==NULL) {
		pid_unalloc(newguy->t_pid); /* ASST1: cleanup pid on fail */
		kfree(newguy->t_name);
		kfree(newguy);
		return ENOMEM;
	}

	/* stick a magic number on the bottom end of the stack */
	newguy->t_stack[0] = 0xae;
	newguy->t_stack[1] = 0x11;
	newguy->t_stack[2] = 0xda;
	newguy->t_stack[3] = 0x33;

	/* Inherit the current directory */
	if (curthread->t_cwd != NULL) {
		VOP_INCREF(curthread->t_cwd);
		newguy->t_cwd = curthread->t_cwd;
	}

	/* ASST1: copy address space if there is one */
	if (curthread->t_vmspace != NULL) {
		result = as_copy(curthread->t_vmspace, &newguy->t_vmspace);
		if (result) {
			pid_unalloc(newguy->t_pid); 
			kfree(newguy->t_name);
			kfree(newguy->t_stack);
			kfree(newguy);			
			return ENOMEM;
		}
	}


	/* Set up the pcb (this arranges for func to be called) */
	md_initpcb(&newguy->t_pcb, newguy->t_stack, data1, data2, func);

	/* Interrupts off for atomicity */
	s = splhigh();

	/*
	 * Make sure our data structures have enough space, so we won't
	 * run out later at an inconvenient time.
	 */
	result = array_preallocate(sleepers, numthreads+1);
	if (result) {
		goto fail;
	}
	result = array_preallocate(zombies, numthreads+1);
	if (result) {
		goto fail;
	}

	/* Do the same for the scheduler. */
	result = scheduler_preallocate(numthreads+1);
	if (result) {
		goto fail;
	}

	/* Make the new thread runnable */
	result = make_runnable(newguy);
	if (result != 0) {
		goto fail;
	}

	/*
	 * Increment the thread counter. This must be done atomically
	 * with the preallocate calls; otherwise the count can be
	 * temporarily too low, which would obviate its reason for
	 * existence.
	 */
	numthreads++;

	/* Done with stuff that needs to be atomic */
	splx(s);

	/*
	 * Return new thread structure if it's wanted.  Note that
	 * using the thread structure from the parent thread should be
	 * done only with caution, because in general the child thread
	 * might exit at any time.
	 */
	if (ret != NULL) {
		*ret = newguy->t_pid; /* ASST1 return pid, not thread struct */
	} else {
		/* Not returning the pid... better detach the new thread */
		result = thread_detach(newguy->t_pid);
		assert(result == 0); /* can't fail. */
	}

	return 0;

 fail:
	splx(s);

	/* ASST1: cleanup pid and vmspace on fail */
	pid_unalloc(newguy->t_pid); 

	if (newguy->t_vmspace) {
		as_destroy(newguy->t_vmspace);
	}

	if (newguy->t_cwd != NULL) {
		VOP_DECREF(newguy->t_cwd);
	}
	kfree(newguy->t_stack);
	kfree(newguy->t_name);
	kfree(newguy);

	return result;
}