void TestComp_deinit(AcCompMgr* cm) { ac_debug_printf(LDR ":+cm=%p comp=%s\n", ldr, cm, test_comp.comp.name); AcReceptor_ret(test_comp.waiting); AcCompMgr_rmv_comp((AcComp*)&test_comp); ac_debug_printf(LDR ":-cm=%p comp=%s\n", ldr, cm, test_comp.comp.name); }
/** * Test dispatching a message * * return AC_TRUE if an error. */ /*static*/ ac_bool test_dispatching() { ac_bool error = AC_FALSE; AcStatus status; ac_debug_printf("test_dispatching:+\n"); // Get a dispatcher AcDispatcher* pd = AcDispatcher_get(1); error |= AC_TEST(pd != AC_NULL); Ac1Comp ac1 = { .comp = { .name=(ac_u8*)"ac1", .process_msg = &ac1_process_msg }, .msg_count = 0, .ac_init_cmd_count = 0, .ac_deinit_cmd_count = 0, .error = 0 }; // Add an acq AcDispatchableComp* dc1; dc1 = AcDispatcher_add_comp(pd, &ac1.comp); error |= AC_TEST(dc1 != AC_NULL); // Initialize a msg pool AcMsgPool mp; status = AcMsgPool_init(&mp, 2, 0); error |= AC_TEST(status == AC_STATUS_OK); // Get a msg and dispatch it AcMsg* msg1; msg1 = AcMsgPool_get_msg(&mp); error |= AC_TEST(msg1 != AC_NULL); msg1->op = 1; AcDispatcher_send_msg(dc1, msg1); ac_debug_printf("test_dispatching: dispatch now\n"); ac_bool processed_msgs = AcDispatcher_dispatch(pd); ac_debug_printf("test_dispatching: dispatch complete\n"); error |= AC_TEST(processed_msgs == AC_TRUE); // Get a second message and dispatch it AcMsg* msg2; msg2 = AcMsgPool_get_msg(&mp); error |= AC_TEST(msg2 != AC_NULL); msg2->op = 1; AcDispatcher_send_msg(dc1, msg2); ac_debug_printf("test_dispatching: rmv_ac\n"); error |= AC_TEST(AcDispatcher_rmv_comp(pd, &ac1.comp) == AC_STATUS_OK); error |= AC_TEST(ac1.error == 0); ac_debug_printf("test_dispatching:- error=%d\n", error); return error; }
AcStatus TestComp_init(AcCompMgr* cm) { AcStatus status; ac_debug_printf(LDR ":+cm=%p comp=%s\n", ldr, cm, test_comp.comp.name); test_comp.cm = cm; test_comp.target_comp_name = (AcU8*)INET_LINK_COMP_IPV4_NAME; test_comp.waiting = AcReceptor_get(); status = AcCompMgr_add_comp(cm, &test_comp.comp); ac_debug_printf(LDR ":-cm=%p comp=%s status=%u\n", ldr, cm, test_comp.comp.name, status); return status; }
void* t1(void *param) { struct test_params* params = (struct test_params*)param; //ac_printf("t1:+params->loops=%d\n", params->loops); for(ac_uint i = 0; i < params->loops; i++) { __atomic_add_fetch(¶ms->counter, 1, __ATOMIC_RELEASE); //ac_thread_yield(); #ifdef NDEBUG // Wait to be signaled AcReceptor_wait(params->receptor); #else if ((i % 1) == 0) { ac_printf("t1: i=%d flags=%x isr_counter=%d receptor.thdl=%x", i, get_flags(), get_timer_reschedule_isr_counter(), params->receptor->thdl); print_ready_list(" - "); } ac_printf("t1: waiting thdl=%x flags=%x\n", ac_thread_get_cur_hdl(), get_flags()); ac_u64 wait_start = ac_tscrd(); AcReceptor_wait(params->receptor); ac_u64 ticks = ac_tscrd() - wait_start; ac_printf("t1: continuing wait time=%.9t\n", ticks); #endif } ac_debug_printf("t1: signal done_receptor\n"); AcReceptor_signal(params->done_receptor); return AC_NULL; }
static ac_bool ac1_process_msg(AcComp* ac, AcMsg* msg) { Ac1Comp* this = (Ac1Comp*)ac; ac_debug_printf("ac1_process_msg:+ msg->arg1=%lx, msg->arg2=%lx\n", msg->arg1, msg->arg2); ac_debug_printf("ac1_process_msg:+\n"); if (msg->op == AC_INIT_CMD) { ac_debug_printf("ac1_process_msg: AC_INIT_CMD\n"); this->ac_init_cmd_count += 1; this->error |= AC_TEST(this->ac_init_cmd_count == 1); this->error |= AC_TEST(this->ac_deinit_cmd_count == 0); } else if (msg->op == AC_DEINIT_CMD) { ac_debug_printf("ac1_process_msg: AC_DEINIT_CMD\n"); this->ac_deinit_cmd_count += 1; this->error |= AC_TEST(this->ac_init_cmd_count == 1); this->error |= AC_TEST(this->ac_deinit_cmd_count == 1); } else { ac_debug_printf("ac1_process_msg: OTHER msg->arg1=%lx, msg->arg2=%lx\n", msg->arg1, msg->arg2); this->msg_count += 1; this->error |= AC_TEST(msg->op == 1); } ac_debug_printf("ac1_process_msg: ret msg=%p\n", msg); AcMsgPool_ret_msg(msg); ac_debug_printf("ac1_process_msg:-error=%d\n", this->error); return AC_TRUE; }
ac_bool work_state(AcComp* comp, AcMsg* msg) { TestComp* this = (TestComp*)comp; ac_debug_printf(LDR ":+msg->op=%lx\n", ldr, msg->op); switch (msg->op) { case SEND_ARP_REQ: { ac_printf(LDR "SEND_ARP_REQ\n", ldr); AcMsg* m = AcMsgPool_get_msg(&this->mp); m->op = AC_INET_SEND_ARP_CMD; AcInetSendArpExtra* send_arp_extra = (AcInetSendArpExtra*)m->extra; send_arp_extra->proto = AC_ETHER_PROTO_IPV4; send_arp_extra->proto_addr_len = AC_IPV4_ADDR_LEN; send_arp_extra->proto_addr[0] = 10; send_arp_extra->proto_addr[1] = 0; send_arp_extra->proto_addr[2] = 0; send_arp_extra->proto_addr[3] = 2; AcCompMgr_send_msg(this->target_comp, m); // Delay a 1/4 second to let it complete //ac_printf(LDR "SEND_ARP_REQ; waiting\n", ldr); ac_thread_wait_ns(250000000); //ac_printf(LDR "SEND_ARP_REQ; done waiting\n", ldr); AcReceptor_signal(this->waiting); break; } case DONE: { ac_printf(LDR "DONE\n", ldr); TRANS_TO(this, done_state); AcReceptor_signal(this->waiting); break; } default: { ac_printf(LDR "unregonized AC_OP=%lx\n", ldr, msg->op); TRANS_TO(this, done_state); break; } } ac_debug_printf(LDR ":-msg->op=%lx\n", ldr, msg->op); AcMsgPool_ret_msg(msg); return AC_TRUE; }
/** * Allocate count elements each at least size long and each aligned * on the alignment value. The value in pRaw is the unaligned pointer * and is passed to ac_free. The value in pAligned is the address of * the first element. * * @param count is the number of elements to create * @param size is the minimum size of each element created * @param alignment is a value to align on, such as AC_MAX_CACHE_LINE_LEN * @param pRaw is the address to return the raw pointer passed to ac_free * @param pAligned is the address to return the aligned pointer of the frist element * @param pElemSize is length of each element which will be a multipel of alignment */ AcStatus ac_calloc_align(AcU32 count, AcU32 size, AcU32 alignment, void** pRaw, void** pAligned, AcU32* pElemSize) { ac_debug_printf("ac_calloc_align:+count=%u size=%u alignment=%u\n" " pRaw=%p pAligned=%p pElemSize=%p\n", count, size, alignment, pRaw, pAligned, pElemSize); AcStatus status; void* raw = AC_NULL; void* aligned = AC_NULL; AcU32 elem_size = 0; AcUptr mask = 0; if ((count == 0) | (size == 0) | (AC_COUNT_ONE_BITS(alignment) != 1) | (pRaw == AC_NULL) | (pAligned == AC_NULL) | (pElemSize == AC_NULL)) { ac_debug_printf("ac_calloc_align: BAD_PARAM\n"); status = AC_STATUS_BAD_PARAM; goto done; } mask = ~((AcUptr)alignment - 1); elem_size = (size + alignment - 1) & mask; AcU64 allocation_size = (elem_size * count) + alignment - 1; raw = ac_calloc(1, allocation_size); if (raw == AC_NULL) { ac_debug_printf("ac_calloc_align: OUT_OF_MEMORY\n"); status = AC_STATUS_OUT_OF_MEMORY; goto done; } aligned = (void*)((((AcUptr)raw) + alignment - 1) & mask); status = AC_STATUS_OK; done: if (status != AC_STATUS_OK) { ac_free(raw); } else { *pRaw = raw; *pAligned = aligned; *pElemSize = elem_size; } ac_debug_printf("ac_calloc_align:-raw=%p aligned=%p elem_size=%u status=%u\n", raw, aligned, elem_size, status); return status; }
ac_bool done_state(AcComp* comp, AcMsg* msg) { TestComp* this = (TestComp*)comp; ac_debug_printf(LDR ":+msg->op=%lx\n", ldr, msg->op); switch (msg->op) { case (AC_DEINIT_CMD): { ac_debug_printf(LDR "AC_DEINIT_CMD\n", ldr); break; } default: { ac_printf(LDR "unregonized AC_OP=%lx\n", ldr, msg->op); break; } } ac_debug_printf(LDR ":-msg->op=%lx\n", ldr, msg->op); AcMsgPool_ret_msg(msg); return AC_TRUE; }
/** * Indentify and clear source of interrupt. * After returning interrupts will be enabled * so we use __atomic operations on source. */ void periodic_iacs(ac_uptr param) { irq_param* pirq_param = (irq_param*)param; ac_u32 timer_ris = ac_timer_rd_ris(pirq_param->timer); if ((timer_ris & 0x1) != 0) { ac_bool* psource = &pirq_param->source; __atomic_store_n(psource, AC_TRUE, __ATOMIC_RELEASE); ac_timer_wr_int_clr(pirq_param->timer); ac_debug_printf("\n\nperiodic: %d cleared\n", pirq_param->timer); } }
AcUint test_inet_link_impl(AcCompMgr* cm) { AcUint error = AC_FALSE; AcMsgPool mp; AcMsg* msg; ac_debug_printf(LDR ":+\n", ldr); // Create a message pool with extra space large enough // for AC_INET_LINK_PROTOCOL messages AcMsgPool_init(&mp, 8, AC_INET_LINK_PROTOCOL_EXTRA_MAX_LEN); // Initialize the test component TestComp_init(cm); #if 0 AcReceptor_wait(test_comp.waiting); if (test_comp.status != AC_STATUS_OK) { ac_debug_printf(LDR "Could not initialize test_comp\n", ldr); goto done; } #endif // Send a ARP Request msg = AcMsgPool_get_msg(&mp); msg->op = SEND_ARP_REQ; AcCompMgr_send_msg(&test_comp.comp, msg); AcReceptor_wait(test_comp.waiting); // Send Done msg = AcMsgPool_get_msg(&mp); msg->op = DONE; AcCompMgr_send_msg(&test_comp.comp, msg); AcReceptor_wait(test_comp.waiting); //done: // Deinitialize the test component TestComp_deinit(cm); AcMsgPool_deinit(&mp); ac_debug_printf(LDR ":-\n", ldr); return error; }
ac_bool initial_state(AcComp* comp, AcMsg* msg) { AcStatus status; TestComp* this = (TestComp*)comp; ac_debug_printf(LDR ":+msg->op=%lx\n", ldr, msg->op); switch (msg->op) { case (AC_INIT_CMD): { ac_debug_printf(LDR "AC_INIT_CMD\n", ldr); // Create a message pool status = AcMsgPool_init(&this->mp, 8, AC_INET_LINK_PROTOCOL_EXTRA_MAX_LEN); if (status != AC_STATUS_OK) { ac_printf(LDR "AC_INIT_CMD could not allocates messages", ldr); this->status = status; TRANS_TO(this, done_state); } ac_debug_printf(LDR "AC_INIT_CMD mp initied\n", ldr); // Find the component we're going to test test_comp.target_comp = AcCompMgr_find_comp(this->cm, this->target_comp_name); if (test_comp.target_comp == AC_NULL) { ac_printf(LDR "AC_INIT_CMD could not find target_comp=%s", ldr, this->target_comp_name); this->status = status; TRANS_TO(this, done_state); } ac_debug_printf(LDR "AC_INIT_CMD found target comp\n", ldr); this->status = AC_STATUS_OK; AcReceptor_signal(this->waiting); TRANS_TO(this, work_state); break; } default: { ac_printf(LDR "unregonized AC_OP=%lx\n", ldr, msg->op); break; } } ac_debug_printf(LDR ":-msg->op=%lx\n", ldr, msg->op); AcMsgPool_ret_msg(msg); return AC_TRUE; }
/** * Handle the one_shot interrupt. * * NOTE: Interrupts are enabled so __atomic operations are used. */ void periodic_handler(ac_uptr param) { irq_param* pirq_param = (irq_param*)param; ac_bool ac_true = AC_TRUE; ac_bool* psource = &pirq_param->source; ac_bool ok = __atomic_compare_exchange_n(psource, &ac_true, AC_FALSE, AC_TRUE, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE); if (ok) { __atomic_add_fetch(&periodic_counter, 1, __ATOMIC_RELEASE); ac_debug_printf("periodic: %d inc counter\n\n", pirq_param->timer); } }
/** * Handle the periodic interrupt. * * NOTE: Interrupts are enabled so __atomic operations are used. */ static void periodic_handler(ac_uptr param) { irq_param* pirq_param = (irq_param*)param; // Test if pirq_param->source is AC_TRUE which means this did fire ac_bool ac_true = AC_TRUE; ac_bool* psource = &pirq_param->source; ac_bool ok = __atomic_compare_exchange_n(psource, &ac_true, AC_FALSE, AC_TRUE, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE); if (ok) { // Yes, this interupt occurred. ac_debug_printf("periodic: %d handled\n", pirq_param->timer); } }
void* t1(void *param) { struct test_params* params = (struct test_params*)param; //ac_printf("t1:+params->loops=%d\n", params->loops); for(ac_uint i = 0; i < params->loops; i++) { __atomic_add_fetch(¶ms->counter, 1, __ATOMIC_RELEASE); //ac_thread_yield(); AcReceptor_wait(params->receptor); } ac_debug_printf("t1: signal done_receptor\n"); AcReceptor_signal(params->done_receptor); return AC_NULL; }
/** * Have the current thread wait for some number of ticks. */ static void thread_wait_timespec(struct timespec* ptime) { // Wait loop while (AC_TRUE) { int rslt = nanosleep(ptime, ptime); //ac_printf("ac_thread_wait: rslt=%d\n", rslt); switch (rslt) { case 0: return; case EINTR: break; default: { ac_debug_printf("ac_thread_wait: errno=%d\n", rslt); return; break; } } } }
/** * @see ac_msg_pool.h */ AcStatus AcMsgPool_init(AcMsgPool* mp, AcU32 msg_count, AcU32 len_extra) { ac_debug_printf("AcMsgPool_init:+mp=%p msg_count=%u len_extra=%u\n", mp, msg_count, len_extra); AcStatus status; if (mp == AC_NULL) { status = AC_STATUS_BAD_PARAM; goto done; } mp->msgs_raw = AC_NULL; mp->next_ptrs_raw = AC_NULL; mp->msgs = AC_NULL; mp->len_extra = len_extra; // Allocate and align the messages AcU32 size_entry; status = ac_calloc_align(msg_count, sizeof(AcMsg) + len_extra, sizeof(AcU64), &mp->msgs_raw, (void**)&mp->msgs, &size_entry); ac_debug_printf("AcMsgPool_init: mp=%p msgs_raw=%p msgs=%p size_entry=%u status=%u\n", mp, mp->msgs_raw, mp->msgs, size_entry, status); if (status != AC_STATUS_OK) { goto done; } // Allocate and align the AcNextPtrs // BUG These AcNextPtrs need to be managed globally. AcU32 size_next_entry; status = ac_calloc_align(msg_count, sizeof(AcNextPtr), AC_MAX_CACHE_LINE_LEN, &mp->next_ptrs_raw, (void**)&mp->next_ptrs, &size_next_entry); ac_debug_printf("AcMsgPool_init: mp=%p next_ptrs_raw=%p next_ptrs=%p size_next_entry=%u status=%u\n", mp, mp->next_ptrs_raw, mp->msgs, size_next_entry, status); if (status != AC_STATUS_OK) { goto done; } // Init the ring buffer status = AcMpscRingBuff_init(&mp->rb, msg_count); if (status != AC_STATUS_OK) { goto done; } // Add messages void* base = mp->msgs; void* base_np = mp->next_ptrs; for (AcU32 i = 0; i < msg_count; i++) { AcMsg* msg = (AcMsg*)base; AcNextPtr* np = (AcNextPtr*)base_np; // Init next_ptr fields np->next = AC_NULL; np->msg = AC_NULL; // Init msg fields msg->mp = mp; msg->next_ptr = np; // Add msg to ring buffer if (!AcMpscRingBuff_add_mem(&mp->rb, msg)) { ac_fail("AcMsgPool_init: WTF should always be able to add msg"); status = AC_STATUS_ERR; goto done; } // Advance to next entries base += size_entry; base_np += size_next_entry; } done: if (status != AC_STATUS_OK && mp != AC_NULL) { ac_free(mp->msgs_raw); ac_free(mp->next_ptrs_raw); } ac_debug_printf("AcMsgPool_init:-mp=%p msg_count=%u len_extra=%u status=%d\n", mp, msg_count, len_extra, status); return status; }
/** * Initialize this module */ void AcInetLink_init(AcCompMgr* cm) { ac_debug_printf("AcInetLink_init:# cm=%p\n", cm); }
ac_uint test_receptor(void) { ac_printf("test_receptor:+\n"); ac_uint error = AC_FALSE; #if AC_PLATFORM == Posix || AC_PLATFORM == pc_x86_64 struct test_params params; ac_printf("test_receptor: call AcReceptor_get\n"); params.receptor = AcReceptor_get(); params.done_receptor = AcReceptor_get(); params.counter = 0; #ifdef NDEBUG params.loops = 1000000; #else params.loops = 10; ac_uint x = 0; #endif ac_thread_rslt_t rslt = ac_thread_create(0, t1, (void*)¶ms); error |= AC_TEST(rslt.status == 0); ac_u64 start = ac_tscrd(); ac_printf("test_receptor: loops=%ld\n", params.loops); for (ac_uint i = 0; i < params.loops; i++) { #ifdef NDEBUG // Wait for params.counter to change, i.e. t1 and incremented the counter // and is waiting for the signal while (__atomic_load_n(¶ms.counter, __ATOMIC_ACQUIRE) <= i) { } AcReceptor_signal_yield_if_waiting(params.receptor); #else // Wait for params.counter to change, i.e. t1 and incremented the counter // and is waiting for the signal while (__atomic_load_n(¶ms.counter, __ATOMIC_ACQUIRE) <= i) { if ((++x % 20000000) == 0) { ac_printf("test_receptor: waiting for counter i=%d x=%d\n", i, x); } //ac_printf("test_receptor: call ac_thread_yield\n"); //ac_thread_yield(); } ac_u64 wait_until = ac_tscrd() + (ac_tsc_freq() / 1); while (ac_tscrd() < wait_until) { if ((++x % 20000000) == 0) { ac_printf("test_receptor: wait until=%ld cur tsc=%ld i=%d x=%d\n", wait_until, ac_tscrd(), i, x); } //ac_thread_yield(); } //ac_printf("test_receptor: signal\n"); ac_u64 signal_start = ac_tscrd(); AcReceptor_signal_yield_if_waiting(params.receptor); ac_u64 ticks = ac_tscrd() - signal_start; ac_printf("test_receptor: signal time=%.9t\n", ticks); #endif } ac_debug_printf("test_receptor: wait on done_receptor x=%d\n", x); AcReceptor_wait(params.done_receptor); ac_debug_printf("test_receptor: continuing done_receptor\n"); ac_u64 stop = ac_tscrd(); ac_u64 ticks = stop - start; ac_printf("test_receptor: ticks=%ld %ld - %ld\n", ticks, stop, start); ac_u64 ticks_per_op = AC_U64_DIV_ROUND_UP(ticks, params.loops); ac_printf("test_receptor: ticks_per_op=%ld(%.9t)\n", ticks_per_op, ticks_per_op); ac_printf("test_receptor: time=%.9t\n", ticks); AcReceptor_ret(params.receptor); #endif ac_printf("test_receptor:-error=%d\n", error); return error; }