📄 osportco.c
字号:
/*
* FILENAME: osportco.c
*
* Copyright 2002 By InterNiche Technologies Inc. All rights reserved
*
* Code to map NicheTask "TK_" macros and other port routines
* to CronOS RTOS on Samsung/ARM SNDS300 board.
*
* MODULE: SNDS300
*
* PORTABLE: no
*/
#include "includes.h" /* from ChronOS directory */
#include "ipport.h" /* from Interniche directory */
#include "osport.h"
#include "zprint.h"
#ifndef CHRONOS
#error - must define CHRONOS in ipport.h to use this file
#endif
#include "in_utils.h"
#include "memwrap.h"
int rcvdq_semaphore; /* fake semaphore */
int freeq_semaphore; /* fake semaphore */
void * net_task_sem_ptr = NULL;
void * receiveq_sem_ptr;
void * freeq_sem_ptr;
/* state of ints, saved by XXlock_net_res() */
int netq_intmask;
INT8U netmain_prio = 0; /* ID of netmain task, for SignalPktDemux() */
extern void samsung_setup(void);
extern int netmain(void);
/* Define C code main entry point. */
void
cmain(void)
{
// signed short result;
samsung_setup(); /* must add */
// OSInit(); /* Init uCOS */
Printu_Net("test printf\r\n");
/* get the uCOS semaphore used for LOCK_NET_RESOURCE(RESID_NET) */
net_task_sem_ptr = (void*)OSSemCreate(1);
if (!net_task_sem_ptr)
panic("net_task_sem_ptr create err");
/* set fake semaphore pointers for RESID_FREEQ and RESID_RCVDQ */
receiveq_sem_ptr = &rcvdq_semaphore;
freeq_sem_ptr = &freeq_semaphore;
/* We have to lock scheduler while creating net tasks. Even though the RTOS
* technically running yet, the ISR hooks to change tasks don't know this.
* Since the UART uses interrupts heavly, we have to resort to this to
* get console output during net_init.
*/
// OSLockNesting++;
OSSchedLock();
if(0 != netmain()) panic("<<<netmain critcal error>>>"); /* Create net tasks */
OSSchedUnlock();
// OSLockNesting--;
// OSStart(); /* Jump to CronOS - Start system; never returns */
// panic("uCOS returned");
}
u_char
uCOS_self(void)
{
/* Return uCOS currently running task ID */
return(OSTCBCur->OSTCBPrio);
}
int rcvdq_locks = 0;
int freeq_locks = 0;
void
LOCK_NET_RESOURCE(void * semptr)
{
INT8U error;
if(semptr == net_task_sem_ptr)
{
/* net task needs a real semaphore */
OSSemPend((OS_EVENT *)net_task_sem_ptr, 0, &error);
if(error)
{
int errct = 0;
/* sometimes we get a "timeout" error even though we passed a zero
* to indicate we'll wait forever. When this happens, try again:
*/
while(error == 10)
{
if(errct++ > 1000)
{
dtrap("osportco 0\n"); /* fatal? */
return;
}
OSSemPend((OS_EVENT *)net_task_sem_ptr, 0, &error);
}
}
}
else if(semptr == receiveq_sem_ptr)
{
/* Other two cases are for locking the rcvdq or free queues. It
* turns out to work fine to just disable ints around queue put|get
* operation. This allows the lock to be done from an ISR, which should
* not be playing with real semaphores. It is only called when an item
* added to the head or delated from the tail of a queue (both very fast)
* so this design does not compromise realtime performance.
*/
rcvdq_locks++;
/* netq_intmask = INTMASK; save interrupt state */
/* INTMASK |= GLOBAL_INT; disable all interrupts (global bit) */
/* EA = 0; disable all interrupts */
OSSchedLock();
}
else if (semptr == freeq_sem_ptr)
{
freeq_locks++;
/* netq_intmask = INTMASK; save interrupt state */
/* INTMASK |= GLOBAL_INT; disable all interrupts (global bit) */
/* EA = 0; disable all interrupts */
OSSchedLock();
}
return;
}
void
UNLOCK_NET_RESOURCE(void * semptr)
{
INT8U error;
if(semptr == net_task_sem_ptr)
{
/* net task uses a real semaphore */
error = OSSemPost((OS_EVENT *)net_task_sem_ptr);
if(error)
{
dtrap("osportco 1\n");
}
}
else if (semptr == receiveq_sem_ptr)
{
rcvdq_locks--;
OSSchedUnlock();
}
else if (semptr == freeq_sem_ptr)
{
freeq_locks--;
OSSchedUnlock();
}
if((freeq_locks + rcvdq_locks) == 0)
/* INTMASK &= ~GLOBAL_INT; enable global interrupt bit */
/* EA = 1; enable global interrupt bit */
return;
}
/*
* Here's the workaround to an unusual quirk of ChonOS - It
* cannot have multiple tasks of the same priority. Networking systems
* are best done with a few threads which have equal priority and thus
* ensure fair CPU sharing without convoluted priority balancing. This
* means we have to guess a priority for each of our net tasks and then
* code tk_yield() to force a non-zero delay (one tick), to ensure that all
* the network tasks get a round-robin slot to do their thing. Of course
* we could alter the code's design to be optimized for a stricly
* prioritized RTOS, but that would penalize all the non-preemptive and
* non-prioritized systems we also support.
*/
extern TK_ENTRY(tk_netmain); /* in netmain.c */
extern long netmain_wakes;
extern TK_ENTRY(tk_keyboard); /* in netmain.c */
extern long keyboard_wakes;
extern TK_ENTRY(tk_nettick); /* in netmain.c */
extern long nettick_wakes;
#define TASK_ARRAY_SIZE 10
/* Build a local array to configure priorities and */
struct prio_map {
TK_ENTRY_PTR(entry);
u_char priority;
} prio_tab[TASK_ARRAY_SIZE] =
{
&(tk_netmain), 17
,&(tk_nettick), 18
/* (yaxon add) */
#ifdef TK_STDIN_DEVICE
,&(tk_keyboard), 19
#endif
};
INT8U app_priority = 8; /* first/next priority to try for application */
int
TK_NEWTASK(struct inet_taskinfo * nettask)
{
INT8U error;
INT8U priority;
OS_STK * stack;
int task_index;
stack = (OS_STK*)npalloc(nettask->stacksize);
if(!stack)
panic("stack alloc");
again: /* retry entry point if we don't get the ID we want */
/* get priority/ID for this task. First see if it's on t of the
* pre-assigned priorities in the prioty[] table; ifnot then give
* it the next application priority.
*/
priority = app_priority++; /* default to app priority */
for(task_index = 0; task_index < TASK_ARRAY_SIZE; task_index++)
{
if(prio_tab[task_index].entry == nettask->entry)
{
priority = prio_tab[task_index].priority; /* assign priority for table */
app_priority--; /* un-used app priority */
break;
}
}
error = OSTaskCreate(
nettask->entry,
NULL,
/* stack + (nettask->stacksize/4),*/ /* note */
stack + (nettask->stacksize/sizeof(OS_STK)),
priority);
if(error == OS_PRIO_EXIST)
goto again;
/* All other errors are fatal */
if(error)
{
Printu_Net("Task create error %d on %s\n", nettask->name);
return -1;
}
nettask->stackbase = (char*)stack;
nettask->priority = priority;
*nettask->tk_ptr = priority;
Printu_Net("Created %s task, prio: %d\n",
(char *)nettask->name, priority);
/* Remember netmain task Id/Priority for SignalPktDemux() */
if(nettask->entry == tk_netmain)
netmain_prio = priority;
return 0;
}
/* rest of file is excluded unkless we're doing lock_net checking */
#ifdef LOCKNET_CHECKING
#include "q.h" /* InterNiche queue defines */
/* locally define external items involved in checking locks */
extern queue rcvdq;
extern queue bigfreeq;
extern queue lilfreeq;
extern int iniche_net_ready;
extern queue mfreeq;
/* FUNCTION: LOCKNET_CHECK()
*
* If the passed queue is one of the sensitive ones then make sure
* the related resource is locked.
*
* PARAM1: queue * q
*
* RETURNS: nothing, panics if test fails
*/
void
LOCKNET_CHECK(struct queue * q)
{
/* Don't start checking until the net is up */
if(!iniche_net_ready)
return;
#ifdef INCLUDE_TCP
#ifndef MINI_TCP
/* On uCOS/Nichestack/TCP builds, check the mbuf free queue is locked
* by the NET_RESID semaphore. If it's not we panic().
*/
if(q == &mfreeq)
{
/* A non-zero from OSSemAccept() means the semaphore was NOT locked */
if(OSSemAccept((OS_EVENT *)net_task_sem_ptr) != 0)
{
panic("net lock");
}
}
#endif /* not MINI_TCP */
#endif /* INCLUDE_TCP */
/* quick return if it's not one of the other sensitive queues */
if((q != &rcvdq) &&
(q != &bigfreeq) &&
(q != &lilfreeq))
{
return;
}
/* Since the MPC860 build uses interrupt disabling to protect these
* queues, we just need to check the Interrupt state. We use IntrDis()
* to get currentinterrupt state. This disables ints, but we don't
* care about that - if they were already disabled it will have no
* effect, and if they were not then we are going to panic().
*/
if(IntrDis()) /* Get current interupt state */
{
panic("lock");
}
return;
}
#endif /* LOCKNET_CHECKING */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -