int32_t _timeout_remaining_get(struct _timeout *timeout) { unsigned int key = irq_lock(); int32_t remaining_ticks; if (timeout->delta_ticks_from_prev == _INACTIVE) { remaining_ticks = 0; } else { /* * compute remaining ticks by walking the timeout list * and summing up the various tick deltas involved */ struct _timeout *t = (struct _timeout *)sys_dlist_peek_head(&_timeout_q); remaining_ticks = t->delta_ticks_from_prev; while (t != timeout) { t = (struct _timeout *)sys_dlist_peek_next(&_timeout_q, &t->node); remaining_ticks += t->delta_ticks_from_prev; } } irq_unlock(key); return _ticks_to_ms(remaining_ticks); }
int32_t nano_timer_ticks_remain(struct nano_timer *timer) { int key = irq_lock(); int32_t remaining_ticks; struct _nano_timeout *t = &timer->timeout_data; sys_dlist_t *timeout_q = &_nanokernel.timeout_q; struct _nano_timeout *iterator; if (t->delta_ticks_from_prev == -1) { remaining_ticks = 0; } else { /* * As nanokernel timeouts are stored in a linked list with * delta_ticks_from_prev, to get the actual number of ticks * remaining for the timer, walk through the timeouts list * and accumulate all the delta_ticks_from_prev values up to * the timer. */ iterator = (struct _nano_timeout *)sys_dlist_peek_head(timeout_q); remaining_ticks = iterator->delta_ticks_from_prev; while (iterator != t) { iterator = (struct _nano_timeout *)sys_dlist_peek_next( timeout_q, &iterator->node); remaining_ticks += iterator->delta_ticks_from_prev; } } irq_unlock(key); return remaining_ticks; }
/** * @brief Prepare a working set of readers/writers * * Prepare a list of "working threads" into/from which the data * will be directly copied. This list is useful as it is used to ... * * 1. avoid double copying * 2. minimize interrupt latency as interrupts are unlocked * while copying data * 3. ensure a timeout can not make the request impossible to satisfy * * The list is populated with previously pended threads that will be ready to * run after the pipe call is complete. * * Important things to remember when reading from the pipe ... * 1. If there are writers int @a wait_q, then the pipe's buffer is full. * 2. Conversely if the pipe's buffer is not full, there are no writers. * 3. The amount of available data in the pipe is the sum the bytes used in * the pipe (@a pipe_space) and all the requests from the waiting writers. * 4. Since data is read from the pipe's buffer first, the working set must * include writers that will (try to) re-fill the pipe's buffer afterwards. * * Important things to remember when writing to the pipe ... * 1. If there are readers in @a wait_q, then the pipe's buffer is empty. * 2. Conversely if the pipe's buffer is not empty, then there are no readers. * 3. The amount of space available in the pipe is the sum of the bytes unused * in the pipe (@a pipe_space) and all the requests from the waiting readers. * * @return false if request is unsatisfiable, otherwise true */ static bool _pipe_xfer_prepare(sys_dlist_t *xfer_list, struct k_thread **waiter, _wait_q_t *wait_q, size_t pipe_space, size_t bytes_to_xfer, size_t min_xfer, s32_t timeout) { sys_dnode_t *node; struct k_thread *thread; struct k_pipe_desc *desc; size_t num_bytes = 0; if (timeout == K_NO_WAIT) { for (node = sys_dlist_peek_head(wait_q); node != NULL; node = sys_dlist_peek_next(wait_q, node)) { thread = (struct k_thread *)node; desc = (struct k_pipe_desc *)thread->base.swap_data; num_bytes += desc->bytes_to_xfer; if (num_bytes >= bytes_to_xfer) { break; } } if (num_bytes + pipe_space < min_xfer) { return false; } } /* * Either @a timeout is not K_NO_WAIT (so the thread may pend) or * the entire request can be satisfied. Generate the working list. */ sys_dlist_init(xfer_list); num_bytes = 0; while ((thread = (struct k_thread *) sys_dlist_peek_head(wait_q))) { desc = (struct k_pipe_desc *)thread->base.swap_data; num_bytes += desc->bytes_to_xfer; if (num_bytes > bytes_to_xfer) { /* * This request can not be fully satisfied. * Do not remove it from the wait_q. * Do not abort its timeout (if applicable). * Do not add it to the transfer list */ break; } /* * This request can be fully satisfied. * Remove it from the wait_q. * Abort its timeout. * Add it to the transfer list. */ _unpend_thread(thread); _abort_thread_timeout(thread); sys_dlist_append(xfer_list, &thread->base.k_q_node); } *waiter = (num_bytes > bytes_to_xfer) ? thread : NULL; return true; }