static void * thread_func(void *param) { thread_t *t = (thread_t *)param; while (1) { if (t->state == DONE) return NULL; task_t *task = NULL; pthread_mutex_lock(&t->task_list_lock); while (RING_EMPTY(&t->tasks, task, link)) { if (t->state == DONE) return NULL; pthread_cond_wait(&t->task_list_aval_cond, &t->task_list_lock); } task = RING_FIRST(&t->tasks); RING_REMOVE(task, link); pthread_mutex_unlock(&t->task_list_lock); if (task) { (*task->func)(&(task->param)); mem_pool_free(t->mem_pool, (void *)task); } } return NULL; }
/** * \brief Process successfully sent packets * \param gmacd Pointer to GMAC Driver instance. */ static void _gmacd_tx_complete_handler(struct _gmacd* gmacd, uint8_t queue) { Gmac* gmac = gmacd->gmac; struct _gmacd_queue* q = &gmacd->queues[queue]; struct _gmac_desc *desc; gmacd_callback_t callback; uint32_t tsr; //printf("<TX>\r\n"); /* Clear status */ tsr = gmac_get_tx_status(gmac); gmac_clear_tx_status(gmac, tsr); while (!RING_EMPTY(q->tx_head, q->tx_tail)) { desc = &q->tx_desc[q->tx_tail]; /* Exit if frame has not been sent yet: * On TX completion, the GMAC set the USED bit only into the * very first buffer descriptor of the sent frame. * Otherwise it updates this descriptor with status error bits. * This is the descriptor writeback. */ if ((desc->status & GMAC_TX_STATUS_USED) == 0) break; /* Process all buffers of the current transmitted frame */ while ((desc->status & GMAC_TX_STATUS_LASTBUF) == 0) { RING_INC(q->tx_tail, q->tx_size); desc = &q->tx_desc[q->tx_tail]; } /* Notify upper layer that a frame has been sent */ if (q->tx_callbacks) { callback = q->tx_callbacks[q->tx_tail]; if (callback) callback(queue, tsr); } /* Go to next frame */ RING_INC(q->tx_tail, q->tx_size); } /* If a wakeup callback has been set, notify upper layer that it can send more packets now */ if (q->tx_wakeup_callback) { if (RING_SPACE(q->tx_head, q->tx_tail, q->tx_size) >= q->tx_wakeup_threshold) { q->tx_wakeup_callback(queue); } } }
void serial_out() { uint8_t *buf; int32_t len; uint32_t now = usb_now(); if (timer_out == now) return; if (RING_EMPTY(&output_ring)) return; len = ring_read_contineous(&output_ring, &buf); cdcacm_data_wx(buf, len); timer_out = now; }
bool thread_pool_is_idle(thread_pool_t *tp) { int i = 0; for (; i < tp->thread_count; i++) { thread_t *t = tp->threads + i; ASSERT(t, "a thread in thread pool is null\n"); pthread_mutex_lock(&(t->task_list_lock)); if (!RING_EMPTY(&(t->tasks), task, link)) { pthread_mutex_unlock(&(t->task_list_lock)); return false; } pthread_mutex_unlock(&(t->task_list_lock)); } return true; }
static int add_task_to_thread(thread_t *t, task_func_t func, void *task_param) { task_t *task = (task_t *)mem_pool_alloc(t->mem_pool); if (!task) return 1; task->func = func; task->param.real_time_param = task_param; task->param.thread_local_data = t->thread_local_data; RING_ELEM_INIT(task, link); pthread_mutex_lock(&t->task_list_lock); if (RING_EMPTY(&t->tasks, task, link)) pthread_cond_signal(&t->task_list_aval_cond); RING_INSERT_TAIL(&t->tasks, task, task, link); pthread_mutex_unlock(&t->task_list_lock); return 0; }
/** * \brief Reset TX queue when errors are detected * \param gmacd Pointer to GMAC Driver instance. */ static void _gmacd_tx_error_handler(struct _gmacd* gmacd, uint8_t queue) { Gmac *gmac = gmacd->gmac; struct _gmacd_queue* q = &gmacd->queues[queue]; struct _gmac_desc* desc; gmacd_callback_t callback; uint32_t tsr; printf("<TXERR>\r\n"); /* Clear TXEN bit into the Network Configuration Register: * this is a workaround to recover from TX lockups that * occur on sama5d4 gmac (r1p24f2) when using scatter-gather. * This issue has never been seen on sama5d4 gmac (r1p31). */ gmac_transmit_enable(gmac, false); /* The following step should be optional since this function is called * directly by the IRQ handler. Indeed, according to Cadence * documentation, the transmission is halted on errors such as * too many retries or transmit under run. * However it would become mandatory if the call of this function * were scheduled as a task by the IRQ handler (this is how Linux * driver works). Then this function might compete with GMACD_Send(). * * Setting bit 10, tx_halt, of the Network Control Register is not enough: * We should wait for bit 3, tx_go, of the Transmit Status Register to * be cleared at transmit completion if a frame is being transmitted. */ gmac_halt_transmission(gmac); while (gmac_get_tx_status(gmac) & GMAC_TSR_TXGO); /* Treat frames in TX queue including the ones that caused the error. */ while (!RING_EMPTY(q->tx_head, q->tx_tail)) { int tx_completed = 0; desc = &q->tx_desc[q->tx_tail]; /* Check USED bit on the very first buffer descriptor to validate * TX completion. */ if (desc->status & GMAC_TX_STATUS_USED) tx_completed = 1; /* Go to the last buffer descriptor of the frame */ while ((desc->status & GMAC_TX_STATUS_LASTBUF) == 0) { RING_INC(q->tx_tail, q->tx_size); desc = &q->tx_desc[q->tx_tail]; } /* Notify upper layer that a frame status */ // TODO: which error to notify? if (q->tx_callbacks) { callback = q->tx_callbacks[q->tx_tail]; if (callback) callback(queue, tx_completed ? GMAC_TSR_TXCOMP : 0); } /* Go to next frame */ RING_INC(q->tx_tail, q->tx_size); } /* Reset TX queue */ _gmacd_reset_tx(gmacd, queue); /* Clear status */ tsr = gmac_get_tx_status(gmac); gmac_clear_tx_status(gmac, tsr); /* Now we are ready to start transmission again */ gmac_transmit_enable(gmac, true); if (q->tx_wakeup_callback) q->tx_wakeup_callback(queue); }