zephyr/kernel
Flavio Ceolin 148769c715 sched: timeout: Do not miss slice timeouts
Time slices don't have a timeout struct associated and stored in
timeout_list. Time slice timeout is direct programmed in the system
clock and tracked in _current_cpu->slice_ticks.

There is one issue where the time slice timeout can be missed because
the system clock is re-programmed to a longer timeout. To this happens,
it is only necessary that the timeout_list is empty (any timeout set)
and a new timeout longer than remaining time slice is set. This is cause
because z_add_timeout does not check for the slice ticks.

The following example spots the issue:

K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
K_THREAD_STACK_ARRAY_DEFINE(tstacks, NUM_THREAD, STACK_SIZE);
K_SEM_DEFINE(sema, 0, NUM_THREAD);

static inline void spin_for_ms(int ms)
{
	uint32_t t32 = k_uptime_get_32();

	while (k_uptime_get_32() - t32 < ms) {
	}
}

static void thread_time_slice(void *p1, void *p2, void *p3)
{
	printk("thread[%d] - Before spin\n", (int)(uintptr_t)p1);

	/* Spinning for longer than slice */
	spin_for_ms(SLICE_SIZE + 20);

	/* The following print should not happen before another
	 * same priority thread starts.
	 */
	printk("thread[%d] - After spinning\n", (int)(uintptr_t)p1);
	k_sem_give(&sema);
}

void main(void)
{
	k_tid_t tid[NUM_THREAD];
	struct k_thread t[NUM_THREAD];
	uint32_t slice_ticks = k_ms_to_ticks_ceil32(SLICE_SIZE);
	int old_prio = k_thread_priority_get(k_current_get());

	/* disable timeslice */
	k_sched_time_slice_set(0, K_PRIO_PREEMPT(0));

	for (int j = 0; j < 2; j++) {
		k_sem_reset(&sema);

		/* update priority for current thread */
		k_thread_priority_set(k_current_get(), K_PRIO_PREEMPT(j));

		/* synchronize to tick boundary */
		k_usleep(1);

		/* create delayed threads with equal preemptive priority */
		for (int i = 0; i < NUM_THREAD; i++) {
			tid[i] = k_thread_create(&t[i], tstacks[i], STACK_SIZE,
						 thread_time_slice, (void *)i, NULL,
						 NULL, K_PRIO_PREEMPT(j), 0,
						 K_NO_WAIT);
		}

		/* enable time slice (and reset the counter!) */
		k_sched_time_slice_set(SLICE_SIZE, K_PRIO_PREEMPT(0));

		/* Spins for while to spend this thread time but not longer */
		/* than a slice. This is important  */
		spin_for_ms(100);

		printk("before sleep\n");
		/* relinquish CPU and wait for each thread to complete */
		k_sleep(K_TICKS(slice_ticks * (NUM_THREAD + 1)));

		for (int i = 0; i < NUM_THREAD; i++) {
			k_sem_take(&sema, K_FOREVER);
		}

		/* test case teardown */
		for (int i = 0; i < NUM_THREAD; i++) {
			k_thread_abort(tid[i]);
		}
		/* disable time slice */
		k_sched_time_slice_set(0, K_PRIO_PREEMPT(0));
	}
	k_thread_priority_set(k_current_get(), old_prio);
}

Signed-off-by: Flavio Ceolin <flavio.ceolin@intel.com>
2021-01-27 16:55:58 -05:00
..
include kernel: add CONFIG_ARCH_MAPS_ALL_RAM 2021-01-23 19:47:23 -05:00
atomic_c.c
banner.c
cache_handlers.c cache: Expand the APIs for cache flushing 2021-01-19 14:31:02 -05:00
CMakeLists.txt kernel: add condition variables 2021-01-19 08:55:47 -05:00
compiler_stack_protect.c tests: coverage: exclude the CODE UNREACHABLE of code coverage 2021-01-15 12:42:00 -05:00
condvar.c kernel: add vrfy hooks to support userspace with condvar 2021-01-19 08:55:47 -05:00
device.c
errno.c
fatal.c debug: coredump: remove z_ prefix for stuff used outside subsys 2021-01-21 22:08:59 -05:00
futex.c
idle.c power: Remove power management conditionals from code 2021-01-22 09:31:20 -05:00
init.c mmu: ensure gperf data is mapped 2021-01-23 19:47:23 -05:00
Kconfig kernel: build: Make TICKLESS_KERNEL depends on TICKLESS_CAPABLE 2021-01-21 17:20:32 -05:00
kheap.c
mailbox.c
mem_domain.c tests: coverage: exclude the CODE UNREACHABLE of code coverage 2021-01-15 12:42:00 -05:00
mem_slab.c
mempool.c z_heap_aligned_alloc(): avoid memory wastage 2021-01-22 10:04:43 -05:00
mmu.c kernel: add CONFIG_ARCH_MAPS_ALL_RAM 2021-01-23 19:47:23 -05:00
msg_q.c
mutex.c
pipes.c
poll.c kernel: poll: remove unreachable code 2021-01-18 11:02:59 -05:00
queue.c
sched.c tests: coverage: exclude the CODE UNREACHABLE of code coverage 2021-01-15 12:42:00 -05:00
sem.c
smp.c tests: coverage: exclude the CODE UNREACHABLE of code coverage 2021-01-15 12:42:00 -05:00
stack.c
system_work_q.c
thread_abort.c tests: coverage: exclude the CODE UNREACHABLE of code coverage 2021-01-15 12:42:00 -05:00
thread.c kernel: const-qualify objects used to calculate delay values 2021-01-22 08:05:26 -06:00
timeout.c sched: timeout: Do not miss slice timeouts 2021-01-27 16:55:58 -05:00
timer.c kernel: const-qualify objects used to calculate delay values 2021-01-22 08:05:26 -06:00
userspace_handler.c
userspace.c kernel: userspace: aligned memory allocation for dynamic objects 2021-01-13 09:43:55 -08:00
version.c
work_q.c kernel: Remove CONFIG_LEGACY_TIMEOUT_API 2021-01-14 21:33:16 -05:00
xip.c linker: arm: Add cortex_m itcm section 2021-01-15 14:51:20 +01:00