<commit_before>/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/* Timer module for Chrome EC operating system */

#include <stdint.h>

#include "task.h"
#include "timer.h"
#include "hwtimer.h"
#include "atomic.h"
#include "console.h"
#include "uart.h"
#include "util.h"

/* high word of the 64-bit timestamp counter  */
static volatile uint32_t clksrc_high;

/* bitmap of currently running timers */
static uint32_t timer_running = 0;

/* deadlines of all timers */
static timestamp_t timer_deadline[TASK_ID_COUNT];
static uint32_t next_deadline = 0xffffffff;

/* Hardware timer routine IRQ number */
static int timer_irq;


static void expire_timer(task_id_t tskid)
{
	/* we are done with this timer */
	atomic_clear(&timer_running, 1<<tskid);
	/* wake up the taks waiting for this timer */
	task_set_event(tskid, TASK_EVENT_TIMER, 0);
}


void process_timers(int overflow)
{
	uint32_t check_timer, running_t0;
	timestamp_t next;
	timestamp_t now;

	if (overflow)
		clksrc_high++;

reprocess_timers:
	next.val = 0xffffffffffffffff;
	now = get_time();
	do {
		/* read atomically the current state of timer running */
		check_timer = running_t0 = timer_running;
		while (check_timer) {
			int tskid = 31 - __builtin_clz(check_timer);

			/* timer has expired ? */
			if (timer_deadline[tskid].val < now.val)
				expire_timer(tskid);
			else if ((timer_deadline[tskid].le.hi == now.le.hi) &&
			         (timer_deadline[tskid].le.lo < next.le.lo))
				next.val = timer_deadline[tskid].val;

			check_timer &= ~(1 << tskid);
		}
	/* if there is a new timer, let's retry */
	} while (timer_running & ~running_t0);

	if (next.le.hi == 0xffffffff) {
		/* no deadline to set */
		__hw_clock_event_clear();
		next_deadline = 0xffffffff;
		return;
	}

	if (next.val <= get_time().val)
		goto reprocess_timers;
	__hw_clock_event_set(next.le.lo);
	next_deadline = next.le.lo;
	//TODO narrow race: deadline might have been reached before
}


void udelay(unsigned us)
{
	timestamp_t deadline = get_time();

	deadline.val += us;
	while (get_time().val < deadline.val) {}
}


int timer_arm(timestamp_t tstamp, task_id_t tskid)
{<commit_msg>close race condition window in expired timer processing<commit_after>/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/* Timer module for Chrome EC operating system */

#include <stdint.h>

#include "task.h"
#include "timer.h"
#include "hwtimer.h"
#include "atomic.h"
#include "console.h"
#include "uart.h"
#include "util.h"

/* high word of the 64-bit timestamp counter  */
static volatile uint32_t clksrc_high;

/* bitmap of currently running timers */
static uint32_t timer_running = 0;

/* deadlines of all timers */
static timestamp_t timer_deadline[TASK_ID_COUNT];
static uint32_t next_deadline = 0xffffffff;

/* Hardware timer routine IRQ number */
static int timer_irq;


static void expire_timer(task_id_t tskid)
{
	/* we are done with this timer */
	atomic_clear(&timer_running, 1<<tskid);
	/* wake up the taks waiting for this timer */
	task_set_event(tskid, TASK_EVENT_TIMER, 0);
}


void process_timers(int overflow)
{
	uint32_t check_timer, running_t0;
	timestamp_t next;
	timestamp_t now;

	if (overflow)
		clksrc_high++;

	do {
		next.val = 0xffffffffffffffff;
		now = get_time();
		do {
			/* read atomically the current state of timer running */
			check_timer = running_t0 = timer_running;
			while (check_timer) {
				int tskid = 31 - __builtin_clz(check_timer);

				/* timer has expired ? */
				if (timer_deadline[tskid].val < now.val)
					expire_timer(tskid);
				else if ((timer_deadline[tskid].le.hi ==
					  now.le.hi) &&
					 (timer_deadline[tskid].le.lo <
					  next.le.lo))
					next.val = timer_deadline[tskid].val;

				check_timer &= ~(1 << tskid);
			}
		/* if there is a new timer, let's retry */
		} while (timer_running & ~running_t0);

		if (next.le.hi == 0xffffffff) {
			/* no deadline to set */
			__hw_clock_event_clear();
			next_deadline = 0xffffffff;
			return;
		}

		__hw_clock_event_set(next.le.lo);
		next_deadline = next.le.lo;
	} while (next.val <= get_time().val);
}


void udelay(unsigned us)
{
	timestamp_t deadline = get_time();

	deadline.val += us;
	while (get_time().val < deadline.val) {}
}


int timer_arm(timestamp_t tstamp, task_id_t tskid)
{
{'fraction_non_alphanumeric': 0.11848552338530066, 'fraction_numerical': 0.012026726057906459, 'mean_word_length': 3.8135048231511255, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 8, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5484858', 'n_tokens_mistral': 1772, 'n_tokens_neox': 1578, 'n_words': 444}