//__attribute__((noinline)) STATIC tcb_x86* thread_create(ac_size_t stack_size, ac_uptr flags, void*(*entry)(void*), void* entry_arg) { ac_uint sv_flags = disable_intr(); tcb_x86* ptcb = AC_NULL; ac_u8* pstack = AC_NULL; int error = 0; // Allocate a stack if (stack_size <= 0) { stack_size = AC_THREAD_STACK_MIN; } if (stack_size < AC_THREAD_STACK_MIN) { error = 1; goto done; } stack_size = (stack_size + 0xff) & ~0xff; pstack = ac_malloc(stack_size); if (pstack == AC_NULL) { ac_printf("thread_create: could not allocate stack\n"); error = 1; // TODO: add AC_STATUS_OOM goto done; } ac_debug_assert(((ac_uptr)pstack & 0xf) == 0); // Get the tcb and initialize the stack frame ptcb = get_tcb(entry, entry_arg); if (ptcb == AC_NULL) { ac_printf("thread_create: no tcb's available\n"); error = 1; // TODO: add AC_STATUS_TO_MANY_THREADS goto done; } ptcb->pstack = pstack; init_stack_frame(pstack, stack_size, flags, entry_trampoline, ptcb, &ptcb->sp, &ptcb->ss); // Add this after pready add_tcb_after(ptcb, pready); done: if (error != 0) { if (pstack != AC_NULL) { ac_free(pstack); } } #if AC_FALSE ac_printf("thread_create: pstack=0x%x stack_size=0x%x tos=0x%x rl=%d\n", pstack, stack_size, pstack + stack_size, get_ready_length()); ac_printf("thread_create:-ptcb=0x%x ready: ", ptcb); print_tcb_list(AC_NULL, pready); #endif restore_intr(sv_flags); return ptcb; }
/** * Allocate num_members * size bytes and initialize to 0. * * @param: count is number of items of size to create * @param: size is the number of bytes in each item * * @return: pointer to the items */ void* ac_calloc(ac_size_t count, ac_size_t size) { ac_size_t total_size = count * size; if (total_size == 0) { // Standard C99 implementations may return AC_NULL or other value // but its undefined behavior if the returned value is used. // Therefore we require ac_calloc(0) to always return AC_NULL return AC_NULL; } else { void* p = ac_malloc(total_size); ac_memset(p, 0, total_size); return p; } }
/** * Initialize module */ void ac_thread_init(ac_u32 max_threads) { // Verify that pthread_t is <= sizeof(ac_uptr) ac_static_assert(sizeof(pthread_t) <= sizeof(ac_uptr), "Expect pthread_t to be the size of a pointer"); ac_assert(max_threads > 0); ac_u32 size = sizeof(ac_threads) + (max_threads * sizeof(ac_tcb)); pthreads = ac_malloc(size); ac_assert(pthreads != AC_NULL); pthreads->max_count = max_threads; for (ac_u32 i = 0; i < pthreads->max_count; i++) { pthreads->tcbs[i].thread_id = AC_THREAD_ID_EMPTY; } }
/** * Initialize this module */ void ac_thread_init(ac_u32 max_threads) { ac_assert(max_threads > 0); max_threads += SYSTEM_THREAD_COUNT; ac_uint flags = disable_intr(); if (max_threads > total_threads) { // Create array of the threads ac_u32 count = max_threads - total_threads; ac_u32 size = sizeof(ac_threads) + (count * sizeof(tcb_x86)); ac_threads* pnew = ac_malloc(size); ac_assert(pnew != AC_NULL); pnew->max_count = count; // Initialize new entries to AC_THREAD_EMPTY for (ac_u32 i = 0; i < count; i++) { tcb_init(&pnew->tcbs[i], AC_THREAD_ID_EMPTY, AC_NULL, AC_NULL); } if (pthreads == AC_NULL) { // Add frist set of threads pnew->pnext = pnew; pnew->pprev = pnew; pthreads = pnew; } else { // Add these new ones to the beginning of the list // by adding after the pthreads then move pthreads ac_threads* ptmp = pthreads->pnext; pnew->pnext = ptmp; pnew->pprev = pthreads; ptmp->pprev = pnew; pthreads->pnext = pnew; // Point pthreads at pnew to make it head of the list pthreads = pnew; } total_threads += max_threads; // Gurantee all threads can wait simultaneously waiting_tcbs_update_max(total_threads); } restore_intr(flags); }
/** * Initialize module */ void ac_thread_init(ac_u32 max_threads) { // Verify that pthread_t is <= sizeof(ac_uptr) ac_static_assert(sizeof(pthread_t) <= sizeof(ac_uptr), "Expect pthread_t to be the size of a pointer"); ac_assert(max_threads > 0); // Add one for the "main" thread max_threads += 1; ac_u32 size = sizeof(ac_threads) + (max_threads * sizeof(ac_tcb)); pthreads = ac_malloc(size); ac_assert(pthreads != AC_NULL); pthreads->max_count = max_threads; for (ac_u32 i = 0; i < pthreads->max_count; i++) { pthreads->tcbs[i].thread_id = AC_THREAD_ID_EMPTY; } // Initialize pthreads->tcb[0] as main thread pthreads->tcbs[0].thread_id = pthread_self(); pthreads->tcbs[0].entry = AC_NULL; pthreads->tcbs[0].entry_arg = AC_NULL; }
int main(void) { ac_bool error = AC_FALSE; // Must return AC_NULL although according to C99 standard a // malloc(0) may return either but undefined behavior happens // if the pointer is used. Therefore we'll defined it as always // returning AC_NULL error |= AC_TEST(ac_malloc(0) == AC_NULL); // Test conditions which attempt allocate too much memory error |= AC_TEST(ac_malloc(((ac_size_t)0) - 1) == AC_NULL); error |= AC_TEST(ac_malloc(((ac_size_t)0) - 2) == AC_NULL); error |= AC_TEST(ac_malloc(((ac_size_t)0) - 63) == AC_NULL); error |= AC_TEST(ac_malloc(((ac_size_t)0) - 64) == AC_NULL); error |= AC_TEST(ac_malloc(((ac_size_t)0) - 65) == AC_NULL); error |= AC_TEST(ac_malloc(((ac_size_t)0) - 66) == AC_NULL); // Test conditions which must succeed as we expect at // least being able to do a few small allocations void* p1 = ac_malloc(1); error |= AC_TEST(ac_malloc(1) != AC_NULL); ac_free(p1); void* p2 = ac_malloc(2); error |= AC_TEST(p2 != AC_NULL); ac_free(p2); void* p63 = ac_malloc(63); error |= AC_TEST(p63 != AC_NULL); ac_free(p63); void* p64 = ac_malloc(64); error |= AC_TEST(p64 != AC_NULL); ac_free(p64); void* p65 = ac_malloc(1); error |= AC_TEST(p65 != AC_NULL); ac_free(p65); if (!error) { // Succeeded ac_printf("OK\n"); } return error; }