int main(void) { volatile0 = 0; ac_bool error = AC_FALSE; /* * Manually test these runtime errors, enable one at a time * and compile and run, each statement should fail. */ //ac_static_assert(1 == 0, "ac_static_assert(1 == 0), should always fail"); //ac_static_assert(volatile0 == 0, "ac_static_assert(volatile0 == 0), should always fail"); // Expect these asserts to fail, but since our ac_fail_impl // does not invoke "stop()" we can use AC_TEST to validate // that they failed (returned AC_TRUE) and PASS. ac_printf("Expect 5 failures vvvvvvvvvvvvvvvvvvvvvvv\n"); error |= AC_TEST(ac_fail("failing")); error |= AC_TEST(ac_assert(0 == 1)); error |= AC_TEST(ac_assert(volatile0 == 1)); error |= AC_TEST(ac_debug_assert(1 == 2)); error |= AC_TEST(ac_debug_assert(volatile0 == 2)); ac_printf("Expect 5 failures ^^^^^^^^^^^^^^^^^^^^^^^\n"); // These should never fail ac_static_assert(0 == 0, "ac_static_assert(0 == 0) should never fail"); error |= AC_TEST(!ac_assert(0 == 0)); error |= AC_TEST(!ac_assert(volatile0 == 0)); if (!error) { // Succeeded ac_printf("OK\n"); } return error; }
/** * 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; } }
/** * Create a thread and invoke the entry passing entry_arg. If * the entry routine returns the thread is considered dead * and will not be rescheduled and its stack is reclamined. * Any other global memory associated with the thread still * exists and is left untouched. * * @param stack_size is 0 a "default" stack size will be used. * @param entry is the routine to run * @param entry_arg is the argument passed to entry. * * @return a ac_thread_rslt contains a status and an opaque ac_thread_hdl_t. * if rslt.status == 0 the thread was created and ac_thread_hdl_t * is valid. */ ac_thread_rslt_t ac_thread_create(ac_size_t stack_size, void*(*entry)(void*), void* entry_arg) { ac_thread_rslt_t rslt; ac_tcb* pthe_tcb = AC_NULL; int error = 0; pthread_attr_t attr; pthread_attr_init(&attr); if (stack_size > 0) { error |= pthread_attr_setstacksize(&attr, (size_t)stack_size); if (error != 0) { goto done; } } // Find an empty slot for (ac_u32 i = 0; i < pthreads->max_count; i++) { pthread_t empty = AC_THREAD_ID_EMPTY; ac_tcb* pcur_tcb = &pthreads->tcbs[i]; pthread_t* pthread_id = &pcur_tcb->thread_id; ac_bool ok = __atomic_compare_exchange_n(pthread_id, &empty, AC_THREAD_ID_NOT_EMPTY, AC_TRUE, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE); if (ok) { pcur_tcb->entry = entry; pcur_tcb->entry_arg = entry_arg; error |= pthread_create((pthread_t *)pthread_id, &attr, entry_trampoline, pcur_tcb); ac_assert(*pthread_id != AC_THREAD_ID_EMPTY); ac_assert(*pthread_id != AC_THREAD_ID_NOT_EMPTY); if (error == 0) { pthe_tcb = pcur_tcb; break; } else { // Mark as empty and try again, although probably won't work __atomic_store_n(pthread_id, AC_THREAD_ID_EMPTY, __ATOMIC_RELEASE); } } } pthread_attr_destroy(&attr); done: rslt.hdl = (ac_thread_hdl_t)pthe_tcb; rslt.status = (rslt.hdl != 0) ? 0 : 1; return (ac_thread_rslt_t)rslt; }
/** * 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; }
/** * Early initialization of this module */ void ac_thread_early_init() { // Initialize timer first, the main reason // is it set slice_default. init_timer(); // Initialize reschedule isr set_intr_handler(RESCHEDULE_ISR_INTR, reschedule_isr); set_intr_handler(TIMER_RESCHEDULE_ISR_INTR, timer_reschedule_isr); // Allocate the initial array total_threads = 0; pthreads = AC_NULL; ac_thread_init(SYSTEM_THREAD_COUNT); ac_assert(pthreads != AC_NULL); pidle_tcb = &pthreads->tcbs[0]; pmain_tcb = &pthreads->tcbs[1]; // Initialize idle and main tcbs tcb_init(pidle_tcb, 0, idle, AC_NULL); tcb_init(pmain_tcb, 1, AC_NULL, AC_NULL); // Initialize idle's stack init_stack_frame(idle_stack, sizeof(idle_stack), DEFAULT_FLAGS, idle, pidle_tcb, &pidle_tcb->sp, &pidle_tcb->ss); // Add main as the initial pready list pmain_tcb->pnext_tcb = pmain_tcb; pmain_tcb->pprev_tcb = pmain_tcb; pready = pmain_tcb; #ifdef SUPPORT_READY_LENGTH ready_length = 1; #endif // Add idle to the pready list add_tcb_after(pidle_tcb, pready); // Initialize waiting tcbs data structures waiting_tcbs_init(SYSTEM_THREAD_COUNT); print_waiting_tcbs(); ac_printf("ac_thread_early_init: pmain=0x%lx pidle=0x%lx rl=%d\n", pmain_tcb, pidle_tcb, get_ready_length()); print_tcb_list("ac_thread_early_init:-ready: ", pready); }