diff gsm-fw/gpf/osl/os_tim_ir.c @ 482:9d80090a9e0c

os_tim_{fl,ir}.c: timer list concurrency interlocks redesigned to something sensible
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Sun, 29 Jun 2014 07:37:22 +0000
parents 5639b4fa8672
children
line wrap: on
line diff
--- a/gsm-fw/gpf/osl/os_tim_ir.c	Sun Jun 29 04:06:24 2014 +0000
+++ b/gsm-fw/gpf/osl/os_tim_ir.c	Sun Jun 29 07:37:22 2014 +0000
@@ -1,6 +1,9 @@
 /*
  * This C module is a reconstruction based on the disassembly of
- * os_tim.obj in frame_na7_db_ir.lib from the Leonardo package.
+ * os_tim.obj in frame_na7_db_ir.lib from the Leonardo package,
+ * subsequently reworked by Space Falcon.
+ *
+ * The original decompilation has been contributed by Das Signal.
  */
 
 /* set of included headers from COFF symtab: */
@@ -19,8 +22,8 @@
 extern unsigned os_time_to_tick_multiplier;
 extern unsigned os_tick_to_time_multiplier;
 
-extern unsigned t_start_ticks;
-extern T_OS_TIMER_TABLE_ENTRY * volatile t_running;
+extern unsigned volatile t_start_ticks;
+extern T_OS_TIMER_TABLE_ENTRY *t_running;
 extern int used_timers;
 extern int next_t_handle;
 extern int volatile t_list_access;
@@ -28,83 +31,15 @@
 extern NU_SEMAPHORE TimSemCB;
 extern NU_TIMER os_timer_cb;
 
+#define	BARRIER	asm volatile ("": : :"memory")
+
 void
 timer_error(int err)
 {
 }
 
-/*
- * The following function reconstructions have been contributed by Das Signal,
- * then reviewed and fixed in a few places by Space Falcon.
- */
-
-void
-os_Timeout(UNSIGNED t_handle)	/* argument is unused */
-{
-	ULONG s_ticks;
-	OS_HANDLE task_handle, e_handle;
-	USHORT t_index;
-	int i, done;
-	T_OS_TIMER_TABLE_ENTRY **t_r4;
-	T_OS_TIMER_TABLE_ENTRY *timer;
-	void (*timeout_func) (OS_HANDLE, OS_HANDLE, USHORT);
-	OS_TIME resched_time;
-
-	if (t_list_access) {
-		t_start_ticks++;
-		NU_Reset_Timer(&os_timer_cb, os_Timeout, 1, 0,
-				NU_ENABLE_TIMER);
-		return;
-	}
-
-	t_list_access = 1;
-	timer = t_running;
-	if (timer) {
-		s_ticks = 0;
-		done = 0;
-		i = 0;
-		do {
-			timeout_func = timer->TimeoutProc;
-			if (timer->p_ticks)
-				p_list[i++] = timer;
-			task_handle = timer->task_handle;
-			e_handle = timer->entity_handle;
-			t_index = timer->t_index;
-			timer->status = TMR_USED;
-			if (timer->next == timer) {
-				t_running = NULL;
-				done = 1;
-			} else {
-				timer->prev->next = timer->next;
-				timer->next->prev = timer->prev;
-				if (timer->next->r_ticks) {
-					t_running = timer->next;
-					s_ticks = timer->next->r_ticks;
-					done = 1;
-				} else
-					timer = timer->next;
-			}
-			timeout_func(task_handle, e_handle, t_index);
-		}
-		while (!done);
-
-		if (s_ticks) {
-			t_start_ticks = NU_Retrieve_Clock();
-			NU_Reset_Timer(&os_timer_cb, os_Timeout, s_ticks, 0,
-				       NU_ENABLE_TIMER);
-		}
-	}
-	for (t_r4 = p_list; *t_r4; t_r4++) {
-		timer = *t_r4;
-		resched_time = SYSTEM_TICKS_TO_TIME(timer->p_ticks);
-		os_StartTimer(timer->entity_handle, timer->t_handle,
-				timer->t_index, resched_time, resched_time);
-		*t_r4 = NULL;
-	}
-
-	t_list_access = 0;
-	return;
-}
+/* forward declaration */
+void os_Timeout(UNSIGNED t_handle);
 
 static int
 os_remove_timer_from_list(T_OS_TIMER_TABLE_ENTRY *timer)
@@ -147,7 +82,7 @@
 os_add_timer_to_list(T_OS_TIMER_TABLE_ENTRY *timer, OS_TICK ticks)
 {
 	T_OS_TIMER_TABLE_ENTRY *t_list;
-	OS_TICK c_ticks, r1_ticks, return_ticks;
+	OS_TICK c_ticks, e_ticks, r1_ticks, return_ticks;
 
 	if (ticks == 0)
 		ticks = 1;
@@ -155,8 +90,9 @@
 	c_ticks = NU_Retrieve_Clock();
 	t_list = t_running;
 	if (t_list != NULL) {
-		if (t_list->r_ticks >= c_ticks - t_start_ticks) {
-			r1_ticks = t_list->r_ticks - c_ticks + t_start_ticks;
+		e_ticks = c_ticks - t_start_ticks;
+		if (t_list->r_ticks >= e_ticks) {
+			r1_ticks = t_list->r_ticks - e_ticks;
 			t_list->r_ticks = r1_ticks;
 		} else {
 			r1_ticks = 0;
@@ -196,30 +132,91 @@
 	return return_ticks;
 }
 
+void
+os_Timeout(UNSIGNED t_handle)	/* argument is unused */
+{
+	ULONG s_ticks;
+	OS_HANDLE task_handle, e_handle;
+	USHORT t_index;
+	int i, done;
+	T_OS_TIMER_TABLE_ENTRY **t_r4;
+	T_OS_TIMER_TABLE_ENTRY *timer;
+	void (*timeout_func) (OS_HANDLE, OS_HANDLE, USHORT);
+
+	if (t_list_access) {
+		t_start_ticks++;
+		NU_Reset_Timer(&os_timer_cb, os_Timeout, 1, 0,
+				NU_ENABLE_TIMER);
+		return;
+	}
+
+	timer = t_running;
+	if (timer) {
+		s_ticks = 0;
+		done = 0;
+		i = 0;
+		do {
+			timeout_func = timer->TimeoutProc;
+			if (timer->p_ticks)
+				p_list[i++] = timer;
+			task_handle = timer->task_handle;
+			e_handle = timer->entity_handle;
+			t_index = timer->t_index;
+			timer->status = TMR_USED;
+			if (timer->next == timer) {
+				t_running = NULL;
+				done = 1;
+			} else {
+				timer->prev->next = timer->next;
+				timer->next->prev = timer->prev;
+				if (timer->next->r_ticks) {
+					t_running = timer->next;
+					s_ticks = timer->next->r_ticks;
+					done = 1;
+				} else
+					timer = timer->next;
+			}
+			timeout_func(task_handle, e_handle, t_index);
+		}
+		while (!done);
+
+		if (s_ticks) {
+			t_start_ticks = NU_Retrieve_Clock();
+			NU_Reset_Timer(&os_timer_cb, os_Timeout, s_ticks, 0,
+				       NU_ENABLE_TIMER);
+		}
+	}
+	for (t_r4 = p_list; *t_r4; t_r4++) {
+		timer = *t_r4;
+		s_ticks = os_add_timer_to_list(timer, timer->p_ticks);
+		if (s_ticks)
+			NU_Reset_Timer(&os_timer_cb, os_Timeout, s_ticks, 0,
+					NU_ENABLE_TIMER);
+		*t_r4 = NULL;
+	}
+}
+
 GLOBAL LONG os_StartTimer(OS_HANDLE TaskHandle, OS_HANDLE TimerHandle,
 				USHORT Index, OS_TIME InitialTime,
 				OS_TIME RescheduleTime)
 {
 	T_OS_TIMER_TABLE_ENTRY *timer;
 	OS_TICK ticks;
-	USHORT status;
 	STATUS sts;
 
-	t_list_access = 1;
+	if (TimerHandle > MaxSimultaneousTimer)
+		return(OS_ERROR);
 	timer = &TimerTable[TimerHandle].entry;
-	if (TimerHandle > MaxSimultaneousTimer || timer->status == TMR_FREE) {
-		t_list_access = 0;
-		return OS_ERROR;
-	}
-
 	sts = NU_Obtain_Semaphore(&TimSemCB, NU_SUSPEND);
-	/* Disassembly reveals this bogon in the original code:
-		if (sts != NU_SUCCESS)
-			os_MyHandle();
-	*/
-	status = timer->status;
-	if (status == TMR_ACTIVE)
-		status = os_remove_timer_from_list(timer);
+	if (timer->status == TMR_FREE) {
+		if (sts == NU_SUCCESS)
+			NU_Release_Semaphore(&TimSemCB);
+		return(OS_ERROR);
+	}
+	t_list_access = 1;
+	BARRIER;
+	if (timer->status == TMR_ACTIVE)
+		os_remove_timer_from_list(timer);
 	timer->t_handle = TimerHandle;
 	timer->task_handle = os_MyHandle();
 	timer->entity_handle = TaskHandle;
@@ -229,9 +226,10 @@
 	if (ticks)
 		NU_Reset_Timer(&os_timer_cb, os_Timeout, ticks, 0,
 				NU_ENABLE_TIMER);
+	BARRIER;
+	t_list_access = 0;
 	if (sts == NU_SUCCESS)
 		NU_Release_Semaphore(&TimSemCB);
-	t_list_access = 0;
 	return OS_OK;
 }
 
@@ -241,19 +239,23 @@
 	T_OS_TIMER_ENTRY *timer_e;
 	STATUS sts;
 
-	t_list_access = 1;
+	if (TimerHandle > MaxSimultaneousTimer)
+		return(OS_ERROR);
 	timer_e = &TimerTable[TimerHandle];
-	if (TimerHandle > MaxSimultaneousTimer ||
-	    timer_e->entry.status == TMR_FREE) {
-		t_list_access = 0;
+	sts = NU_Obtain_Semaphore(&TimSemCB, NU_SUSPEND);
+	if (timer_e->entry.status == TMR_FREE) {
+		if (sts == NU_SUCCESS)
+			NU_Release_Semaphore(&TimSemCB);
 		return OS_ERROR;
 	}
-	sts = NU_Obtain_Semaphore(&TimSemCB, NU_SUSPEND);
+	t_list_access = 1;
+	BARRIER;
 	if (timer_e->entry.status == TMR_ACTIVE)
 		os_remove_timer_from_list(&timer_e->entry);
+	BARRIER;
+	t_list_access = 0;
 	if (sts == NU_SUCCESS)
 		NU_Release_Semaphore(&TimSemCB);
-	t_list_access = 0;
 	return OS_OK;
 }
 
@@ -268,21 +270,19 @@
 	STATUS sts;
 	T_OS_TIMER_ENTRY *timer_e;
 
-	t_list_access = 1;
+	if (TimerHandle > MaxSimultaneousTimer)
+		return(OS_ERROR);
 	sts = NU_Obtain_Semaphore(&TimSemCB, NU_SUSPEND);
 	timer_e = &TimerTable[TimerHandle];
-	if (TimerHandle > MaxSimultaneousTimer ||
-	    timer_e->entry.status == TMR_FREE) {
+	if (timer_e->entry.status != TMR_USED) {
 		if (sts == NU_SUCCESS)
 			NU_Release_Semaphore(&TimSemCB);
-		t_list_access = 0;
 		return OS_ERROR;
 	}
 	timer_e->next_t_handle = next_t_handle;
 	next_t_handle = TimerHandle;
 	timer_e->entry.status = TMR_FREE;
 	used_timers--;
-	t_list_access = 0;
 	if (sts == NU_SUCCESS)
 		NU_Release_Semaphore(&TimSemCB);
 	return OS_OK;
@@ -296,12 +296,10 @@
 	STATUS sts;
 	T_OS_TIMER_ENTRY *timer_e;
 
-	t_list_access = 1;
 	sts = NU_Obtain_Semaphore(&TimSemCB, NU_SUSPEND);
 	if (next_t_handle == 0) { /* no free timers left */
 		if (sts == NU_SUCCESS)
 			NU_Release_Semaphore(&TimSemCB);
-		t_list_access = 0;
 		return OS_ERROR;
 	}
 
@@ -315,6 +313,5 @@
 		max_used_timers = used_timers;
 	if (sts == NU_SUCCESS)
 		NU_Release_Semaphore(&TimSemCB);
-	t_list_access = 0;
 	return OS_OK;
 }