|
From: <jmk...@us...> - 2003-08-13 06:06:00
|
Update of /cvsroot/emc/rtapi/src/rtapi
In directory sc8-pr-cvs1:/tmp/cvs-serv29419/src/rtapi
Modified Files:
Makefile rtai_rtapi.c rtapi.h
Log Message:
major changes to tasks API. Task IDs are now ints, not pointers. More changes on the way. RTAI builds and examples work. RTLinux and sim will be updated once rtai is done.
Index: Makefile
===================================================================
RCS file: /cvsroot/emc/rtapi/src/rtapi/Makefile,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** Makefile 19 Jul 2003 02:17:41 -0000 1.3
--- Makefile 13 Aug 2003 05:55:07 -0000 1.4
***************
*** 9,14 ****
rtl_rtapi.c \
rtl_ulapi.c \
! sim_rtapi.c \
! sim_ulapi.c
HEADERS = \
--- 9,15 ----
rtl_rtapi.c \
rtl_ulapi.c \
! # TEMPORARY - not making the sim right now
! #sim_rtapi.c \
! #sim_ulapi.c
HEADERS = \
***************
*** 19,24 ****
OBJS = \
! $(LIB_DIR)/sim_rtapi.o \
! $(LIB_DIR)/sim_ulapi.o
# no LIBS, BINS yet
--- 20,26 ----
OBJS = \
! # TEMPORARY - not making the sim right now
! #$(LIB_DIR)/sim_rtapi.o \
! #$(LIB_DIR)/sim_ulapi.o
# no LIBS, BINS yet
***************
*** 81,86 ****
/home/John/emcdev/rtapi/lib/rtl_rtapi.o: rtapi.h
/home/John/emcdev/rtapi/lib/rtl_ulapi.o: ulapi.h
- /home/John/emcdev/rtapi/lib/sim_rtapi.o: rtapi.h
- /home/John/emcdev/rtapi/lib/sim_ulapi.o: ulapi.h
/home/John/emcdev/rtapi/rtlib/rtai_rtapi.o: rtapi.h
--- 83,86 ----
***************
*** 88,91 ****
/home/John/emcdev/rtapi/rtlib/rtl_rtapi.o: rtapi.h
/home/John/emcdev/rtapi/rtlib/rtl_ulapi.o: ulapi.h
- /home/John/emcdev/rtapi/rtlib/sim_rtapi.o: rtapi.h
- /home/John/emcdev/rtapi/rtlib/sim_ulapi.o: ulapi.h
--- 88,89 ----
Index: rtai_rtapi.c
===================================================================
RCS file: /cvsroot/emc/rtapi/src/rtapi/rtai_rtapi.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -C2 -d -r1.21 -r1.22
*** rtai_rtapi.c 12 Aug 2003 21:28:22 -0000 1.21
--- rtai_rtapi.c 13 Aug 2003 05:55:07 -0000 1.22
***************
*** 79,87 ****
/* Task handles are pointers to these structs. */
! struct rtapi_task {
! int magic; /* to check for valid handle */
! int started; /* flag set if task has started */
! RT_TASK ostask; /* OS specific task data */
! };
struct rtapi_shmem {
--- 79,89 ----
/* Task handles are pointers to these structs. */
! typedef enum { EMPTY, PAUSED, PERIODIC, FREERUN, ENDED } state_t;
!
! typedef struct {
! state_t state; /* task state */
! void *taskcode; /* task code */
! RT_TASK *ostask; /* pointer to OS specific task data */
! } task_data;
struct rtapi_shmem {
***************
*** 104,109 ****
};
! #define TASK_MAGIC 21979 /* random numbers used as signatures */
! #define SHMEM_MAGIC 25453
#define SEM_MAGIC 27594
#define FIFO_MAGIC 10293
--- 106,110 ----
};
! #define SHMEM_MAGIC 25453 /* random numbers used as signatures */
#define SEM_MAGIC 27594
#define FIFO_MAGIC 10293
***************
*** 117,121 ****
/* lists of resources */
! static rtapi_task_handle task_array[RTAPI_MAX_TASKS];
static rtapi_shmem_handle shmem_array[RTAPI_MAX_SHMEMS];
static rtapi_sem_handle sem_array[RTAPI_MAX_SEMS];
--- 118,122 ----
/* lists of resources */
! static task_data task_array[RTAPI_MAX_TASKS];
static rtapi_shmem_handle shmem_array[RTAPI_MAX_SHMEMS];
static rtapi_sem_handle sem_array[RTAPI_MAX_SEMS];
***************
*** 147,154 ****
but the process is the same... */
! static struct proc_dir_entry *rtapi_proc; /* struct for proc_fs entities */
! static char proc_data[2]; /* Space for one char plus EOF */
! static int proc_read_rtapi(char *page, char **start, off_t off,
! int count, int *eof, void *data)
{
PROC_PRINT_VARS;
--- 148,158 ----
but the process is the same... */
! static struct proc_dir_entry *rtapi_dir = 0; /* /proc/rtapi directory */
! static struct proc_dir_entry *status_file = 0; /* /proc/rtapi/status */
! static struct proc_dir_entry *tasks_file = 0; /* /proc/rtapi/tasks */
! static struct proc_dir_entry *debug_file = 0; /* /proc/rtapi/debug */
!
! static int proc_read_status(char *page, char **start, off_t off,
! int count, int *eof, void *data)
{
PROC_PRINT_VARS;
***************
*** 156,163 ****
PROC_PRINT(" Version = $Revision$\n");
PROC_PRINT(" Modules Loaded = %i\n", rtapi_usage_count);
! PROC_PRINT(" Tasks running = %i\n", task_usage_count);
! PROC_PRINT(" Shared memory = %i\n", shmem_usage_count);
! PROC_PRINT(" FIFO count = %i\n", fifo_usage_count);
! PROC_PRINT(" Semaphores used = %i\n", sem_usage_count);
PROC_PRINT("Active Interrupts = %i\n", int_usage_count);
PROC_PRINT(" Timer period = %li nSec\n", timer_period);
--- 160,167 ----
PROC_PRINT(" Version = $Revision$\n");
PROC_PRINT(" Modules Loaded = %i\n", rtapi_usage_count);
! PROC_PRINT(" Tasks running = %i/%i\n", task_usage_count, RTAPI_MAX_TASKS);
! PROC_PRINT(" Shared memory = %i/%i\n", shmem_usage_count, RTAPI_MAX_SHMEMS);
! PROC_PRINT(" FIFO count = %i/%i\n", fifo_usage_count, RTAPI_MAX_FIFOS);
! PROC_PRINT(" Semaphores used = %i/%i\n", sem_usage_count, RTAPI_MAX_SEMS);
PROC_PRINT("Active Interrupts = %i\n", int_usage_count);
PROC_PRINT(" Timer period = %li nSec\n", timer_period);
***************
*** 172,208 ****
}
! static int proc_write_rtapi(struct file *file,
const char *buffer,
unsigned long count, void *data)
{
! int len;
! char *buf = data; /* Pointer to the data buffer */
! char temp;
! if (count > 2) { /* If more data than expected is present */
! len = 2; /* just use the first char.. */
! } else {
! len = count;
! }
! if (copy_from_user(buf, buffer, len)) { /* copy from user space */
return -1;
}
! sscanf(data, "%s", &temp);
! if (isdigit(temp)) { /* check it is a number */
! /* Kernel implimentation of strtoul is used here.. */
! rtapi_msg_level = (int) simple_strtoul(&temp, NULL, 0);
}
! return len;
}
! #endif
/* For RTAI, all init is done when the rtapi kernel module
is insmoded. The rtapi_init() and rtapi_exit() functions
! do nothing. For other RTOSes, things might be different,
! especially if the RTOS does not use modules. */
/* NOTE: I decided not to use the MOD_INC_USE_COUNT macros at
--- 176,312 ----
}
!
! static int proc_read_tasks(char *page, char **start, off_t off,
! int count, int *eof, void *data)
! {
! int n;
! char *state_str;
!
! PROC_PRINT_VARS;
! PROC_PRINT("******* RTAPI TASKS *******\n");
! PROC_PRINT("ID State Code\n");
! for ( n = 0 ; n < RTAPI_MAX_TASKS ; n++ ) {
! if ( task_array[n].state != EMPTY ) {
! switch ( task_array[n].state ) {
! case PAUSED:
! state_str = "PAUSED ";
! break;
! case PERIODIC:
! state_str = "PERIODIC";
! break;
! case FREERUN:
! state_str = "FREE RUN";
! break;
! case ENDED:
! state_str = "ENDED ";
! break;
! default:
! state_str = "UNKNOWN ";
! break;
! }
! PROC_PRINT("%02d %s %p\n", n, state_str, task_array[n].taskcode);
! }
! }
! PROC_PRINT("\n");
! PROC_PRINT_DONE;
! }
!
!
! static int proc_read_debug(char *page, char **start, off_t off,
! int count, int *eof, void *data)
! {
! PROC_PRINT_VARS;
! PROC_PRINT("RTAPI Debug Message Level: %i\n", rtapi_msg_level);
! PROC_PRINT_DONE;
! }
!
!
! static int proc_write_debug(struct file *file,
const char *buffer,
unsigned long count, void *data)
{
! char c;
! /* copy 1 byte from user space */
! if (copy_from_user(&c, buffer, 1)) {
return -1;
}
+ /* check it is a digit */
+ if (isdigit(c)) {
+ /* convert to a number */
+ rtapi_msg_level = (int) (c - '0');
+ }
+ /* tell whoever called us that we used all the data, even
+ though we really only used the first byte */
+ return count;
+ }
!
! static int proc_init(void)
! {
! /* create the rtapi directory "/proc/rtapi" */
! rtapi_dir = proc_mkdir("rtapi", NULL);
! if ( rtapi_dir == 0 ) {
! return -1;
}
+ rtapi_dir->owner = THIS_MODULE;
+ /* create read only file "/proc/rtapi/status" using convenience function */
+ status_file = create_proc_read_entry("status", 0444, rtapi_dir,
+ proc_read_status, NULL);
+ if ( status_file == NULL) {
+ return -1;
+ }
+ status_file->owner = THIS_MODULE;
+ /* create read only file "/proc/rtapi/tasks" using convenience function */
+ tasks_file = create_proc_read_entry("tasks", 0444, rtapi_dir,
+ proc_read_tasks, NULL);
+ if ( tasks_file == NULL) {
+ return -1;
+ }
+ tasks_file->owner = THIS_MODULE;
+ /* create read/write file "/proc/rtapi/debug" using regular function */
+ debug_file = create_proc_entry("debug", 0644, rtapi_dir );
+ if ( debug_file == NULL) {
+ return -1;
+ }
+ debug_file->owner = THIS_MODULE;
+ debug_file->data = NULL;
+ debug_file->read_proc = proc_read_debug;
+ debug_file->write_proc = proc_write_debug;
+ return 0;
+ }
! static void proc_clean(void)
! {
! /* remove /proc entries, only if they exist */
! if (rtapi_dir != NULL) {
! if (debug_file != NULL) {
! remove_proc_entry("debug", rtapi_dir);
! debug_file = NULL;
! }
! if (status_file != NULL) {
! remove_proc_entry("status", rtapi_dir);
! status_file = NULL;
! }
! if (tasks_file != NULL) {
! remove_proc_entry("tasks", rtapi_dir);
! tasks_file = NULL;
! }
! remove_proc_entry("rtapi", NULL);
! }
}
! #endif /* CONFIG_PROC_FS */
!
! /***********************************************************************
! * GENERAL PURPOSE FUNCTIONS *
! ************************************************************************/
/* For RTAI, all init is done when the rtapi kernel module
is insmoded. The rtapi_init() and rtapi_exit() functions
! do very little, mostly simply register that another module
! is using the RTAPI. For other RTOSes, things might be
! different, especially if the RTOS does not use modules. */
/* NOTE: I decided not to use the MOD_INC_USE_COUNT macros at
***************
*** 238,241 ****
--- 342,346 ----
}
+
/* here is where the real init happens */
***************
*** 248,267 ****
/* say hello */
rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: Initing\n");
- /* register a proc entry */
#ifdef CONFIG_PROC_FS
! rtapi_proc = create_proc_entry("rtapi", 0644, NULL);
!
! if (rtapi_proc != NULL) { /* It isn't a fatal error if create_proc fails */
! rtapi_proc->data = &proc_data; /* workspace for the input data */
! rtapi_proc->read_proc = proc_read_rtapi; /* The read function */
! rtapi_proc->write_proc = proc_write_rtapi; /* and the write function */
! rtapi_proc->owner = THIS_MODULE;
! } else {
! rtapi_print_msg(RTAPI_MSG_WARN, "Could not open /proc/rtapi\n");
}
#endif
/* clear all the resource arrays */
for (n = 0; n < RTAPI_MAX_TASKS; n++) {
! task_array[n] = NULL;
}
for (n = 0; n < RTAPI_MAX_SHMEMS; n++) {
--- 353,365 ----
/* say hello */
rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: Initing\n");
#ifdef CONFIG_PROC_FS
! if ( proc_init() != 0 ) {
! rtapi_print_msg(RTAPI_MSG_WARN, "Could not activate /proc entries\n");
! proc_clean();
}
#endif
/* clear all the resource arrays */
for (n = 0; n < RTAPI_MAX_TASKS; n++) {
! task_array[n].state = EMPTY;
}
for (n = 0; n < RTAPI_MAX_SHMEMS; n++) {
***************
*** 288,291 ****
--- 386,392 ----
+ /* This cleanup code attempts to fix any messes left by modules
+ that fail to load properly, or fail to clean up after themselves */
+
void cleanup_module(void)
{
***************
*** 337,342 ****
/* clean up leftover tasks */
for (n = 0; n < RTAPI_MAX_TASKS; n++) {
! if (task_array[n] != NULL) {
! rtapi_task_delete(task_array[n]);
}
}
--- 438,443 ----
/* clean up leftover tasks */
for (n = 0; n < RTAPI_MAX_TASKS; n++) {
! if (task_array[n].state != EMPTY) {
! rtapi_task_delete(n);
}
}
***************
*** 353,361 ****
timer_running = 0;
}
- /* Remove proc dir entry */
#ifdef CONFIG_PROC_FS
! if (rtapi_proc != NULL) {
! remove_proc_entry("rtai/rtapi", NULL);
! }
#endif
rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: Exit complete\n");
--- 454,459 ----
timer_running = 0;
}
#ifdef CONFIG_PROC_FS
! proc_clean();
#endif
rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: Exit complete\n");
***************
*** 364,367 ****
--- 462,501 ----
+ /***********************************************************************
+ * CLOCK RELATED FUNCTIONS *
+ ************************************************************************/
+
+ int rtapi_clock_set_period(unsigned long int nsecs)
+ {
+
+ /* limit to a maximum of 1 second (note that RTLinux only
+ allows 0.01 second, so for portability, callers should
+ always ask for 0.01 second or less */
+
+ if (nsecs > 1000000000L) {
+ return RTAPI_INVAL;
+ }
+
+ timer_running = 1;
+ rt_set_periodic_mode();
+ timer_period = count2nano(start_rt_timer(nano2count((RTIME) nsecs)));
+
+ rtapi_print_msg(RTAPI_MSG_INFO,
+ "RTAPI: clock_set_period requested: %d actual: %d\n",
+ nsecs, timer_period);
+
+ return timer_period;
+ }
+
+
+ long long int rtapi_get_time(void)
+ {
+ return rt_get_time_ns();
+ }
+
+ /***********************************************************************
+ * TASK RELATED FUNCTIONS *
+ ************************************************************************/
+
/* Priority functions. RTAI uses 0 as the highest priority, as the
number increases, the actual priority of the task decreases. */
***************
*** 408,679 ****
! int rtapi_clock_set_period(unsigned long int nsecs)
! {
!
! /* limit to a maximum of 1 second (note that RTLinux only
! allows 0.01 second, so for portability, callers should
! always ask for 0.01 second or less */
!
! if (nsecs > 1000000000L) {
! return RTAPI_INVAL;
! }
!
! timer_running = 1;
! rt_set_periodic_mode();
! timer_period = count2nano(start_rt_timer(nano2count((RTIME) nsecs)));
!
! rtapi_print_msg(RTAPI_MSG_INFO,
! "RTAPI: clock_set_period requested: %d actual: %d\n",
! nsecs, timer_period);
!
! return timer_period;
! }
!
! long long int rtapi_get_time(void)
! {
! return rt_get_time_ns();
! }
!
!
! int rtapi_task_new(rtapi_task_handle * taskptr)
{
- rtapi_task_handle task;
int n;
- /* validate taskptr */
- if (taskptr == NULL) {
- return RTAPI_INVAL;
- }
/* find empty spot in task array */
n = 0;
! while ((n < RTAPI_MAX_TASKS) && (task_array[n] != NULL)) {
n++;
}
if (n == RTAPI_MAX_TASKS) {
! return RTAPI_NOMEM;
}
! /* alloc space for task structure */
! task = kmalloc(sizeof(struct rtapi_task), GFP_USER);
! if (task == NULL) {
return RTAPI_NOMEM;
}
! /* add to task array */
! task_array[n] = task;
! /* initialize task structure */
! task->magic = TASK_MAGIC;
! task->started = 0;
! /* increment the usage counter */
task_usage_count++;
! /* and return handle to the caller */
! *taskptr = task;
! rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: new_task %p, count = %d\n",
! task, task_usage_count);
! return RTAPI_SUCCESS;
}
! int rtapi_task_delete(rtapi_task_handle task)
{
! int n, retval;
! /* validate task handle */
! if (task == NULL) {
! return RTAPI_BADH;
! }
! if (task->magic != TASK_MAGIC) {
! return RTAPI_BADH;
! }
! /* find entry in task array */
! n = 0;
! while ((n < RTAPI_MAX_TASKS) && (task_array[n] != task)) {
! n++;
}
! if (n == RTAPI_MAX_TASKS) {
return RTAPI_INVAL;
}
! /* make sure task is stopped */
! if (task->started != 0) {
! /* stop it */
rtapi_print_msg(RTAPI_MSG_WARN,
! "RTAPI: WARNING: tried to delete_task %p, while running\n",
! task);
! retval = rtapi_task_stop(task);
! if (retval != RTAPI_SUCCESS) {
! return retval;
! }
}
! /* free the task struct */
! task->magic = 0;
! kfree(task);
! /* mark the array entry unused */
! task_array[n] = NULL;
! /* decrement the usage counter */
task_usage_count--;
/* done */
! rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: delete_task %p, count = %d\n",
! task, task_usage_count);
return RTAPI_SUCCESS;
}
! int rtapi_task_start(rtapi_task_handle task,
! void (*taskcode) (int),
! int arg, int prio,
! unsigned long int stacksize,
unsigned long int period_nsec,
! unsigned long long when, unsigned char uses_fp)
{
int retval;
! /* validate task handle */
! if (task == NULL) {
! return RTAPI_BADH;
! }
! if (task->magic != TASK_MAGIC) {
! return RTAPI_BADH;
}
! /* check requested priority */
! if ((prio < rtapi_prio_highest()) || (prio > rtapi_prio_lowest())) {
return RTAPI_INVAL;
}
! /* call OS to initialize the task */
! retval = rt_task_init(&(task->ostask), taskcode, arg,
! stacksize, prio, (int) uses_fp, 0);
! if (retval != 0) {
! if (retval == EINVAL) {
! /* task already in use */
! return RTAPI_BUSY;
! }
! if (retval == ENOMEM) {
! /* not enough space for stack */
! return RTAPI_NOMEM;
! }
! /* unknown error */
! return RTAPI_FAIL;
! }
! if (period_nsec > 0) {
! /* periodic task */
! if (when == RTAPI_NOW) {
! /* start the task immediately */
! retval = rt_task_make_periodic(&(task->ostask), rt_get_time(),
! nano2count((RTIME) period_nsec));
! if (retval != 0) {
! return RTAPI_FAIL;
! }
! } else {
! /* schedule the task to start when requested */
! retval = rt_task_make_periodic(&(task->ostask),
! nano2count((RTIME) when),
! nano2count((RTIME) period_nsec));
! if (retval != 0) {
! return RTAPI_FAIL;
! }
! /* check to see if we got done in time */
! if (rt_get_time() > nano2count((RTIME) when)) {
! retval = RTAPI_LATE;
! }
}
} else {
! /* If we got this far, a task has been paused and is awaiting
! a wakeup call to resume */
! retval = rt_task_resume(&(task->ostask));
if (retval != 0) {
return RTAPI_FAIL;
}
}
! task->started = 1;
! rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: start_task %p\n", task);
return retval;
}
! int rtapi_task_stop(rtapi_task_handle task)
{
! int retval;
!
! /* validate task handle */
! if (task == NULL) {
! return RTAPI_BADH;
! }
! if (task->magic != TASK_MAGIC) {
! return RTAPI_BADH;
! }
! /* stop execution of the task */
! retval = rt_task_suspend(&(task->ostask));
! if (retval != 0) {
! return RTAPI_FAIL;
! }
! /* get rid of it */
! retval = rt_task_delete(&(task->ostask));
! if (retval != 0) {
! return RTAPI_FAIL;
! }
! /* done */
! task->started = 0;
! rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: stop_task %p\n", task);
return RTAPI_SUCCESS;
}
! int rtapi_task_pause(rtapi_task_handle task)
{
int retval;
! /* validate task handle */
! if (task == NULL) {
! return RTAPI_BADH;
}
! if (task->magic != TASK_MAGIC) {
! return RTAPI_BADH;
}
! /* FIXME - depending on the version of rtai, a single
! call to resume() may or may not cancel multiple calls
! to suspend(). */
! retval = rt_task_suspend(&(task->ostask));
if (retval != 0) {
return RTAPI_FAIL;
}
return RTAPI_SUCCESS;
}
! int rtapi_task_resume(rtapi_task_handle task)
{
int retval;
! /* validate task handle */
! if (task == NULL) {
! return RTAPI_BADH;
}
! if (task->magic != TASK_MAGIC) {
! return RTAPI_BADH;
}
! /* FIXME - depending on the version of rtai, a single
! call to resume() may or may not cancel multiple calls
! to suspend(). */
! retval = rt_task_resume(&(task->ostask));
if (retval != 0) {
return RTAPI_FAIL;
}
return RTAPI_SUCCESS;
}
! int rtapi_wait(void)
! {
! rt_task_wait_period();
! return RTAPI_SUCCESS;
! }
!
!
! int rtapi_task_get_handle(rtapi_task_handle * taskptr)
{
RT_TASK *ptr;
int n;
- /* validate taskptr */
- if (taskptr == NULL) {
- return RTAPI_INVAL;
- }
/* ask OS for pointer to its data for the current task */
ptr = rt_whoami();
--- 542,751 ----
! int rtapi_task_new(void (*taskcode) (int),
! int arg, int prio,
! unsigned long int stacksize,
! int uses_fp)
{
int n;
+ int task_id;
+ int retval;
+ task_data *task;
/* find empty spot in task array */
n = 0;
! while ((n < RTAPI_MAX_TASKS) &&
! (task_array[n].state != EMPTY)) {
n++;
}
if (n == RTAPI_MAX_TASKS) {
! /* no room */
! return RTAPI_LIMIT;
}
! /* we have space for the task */
! task_id = n;
! task = &(task_array[n]);
! /* check requested priority */
! if ((prio < rtapi_prio_highest()) || (prio > rtapi_prio_lowest())) {
! return RTAPI_INVAL;
! }
! /* get space for the OS's task data - this is around 900 bytes, */
! /* so we don't want to statically allocate it for unused tasks. */
! task->ostask = kmalloc(sizeof(RT_TASK), GFP_USER);
! if (task->ostask == NULL) {
return RTAPI_NOMEM;
}
! /* call OS to initialize the task - use CPU 0 (the only CPU if
! uni-processor, but I want predictable behavior under SMP) */
! retval = rt_task_init_cpuid(task->ostask, taskcode, arg,
! stacksize, prio, uses_fp,
! 0, /* signal */
! 0 /* cpu id */ );
! if (retval != 0) {
! if (retval == ENOMEM) {
! /* not enough space for stack */
! return RTAPI_NOMEM;
! }
! /* unknown error */
! return RTAPI_FAIL;
! }
! /* the task has been created, update data */
! task->state = PAUSED;
! task->taskcode = taskcode;
task_usage_count++;
! /* announce the birth of a brand new baby task */
! rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: new_task id: %d, count: %d, code: %p\n",
! task_id, task_usage_count, taskcode);
! /* and return the ID to the proud parent */
! return task_id;
}
! int rtapi_task_delete(task_id)
{
! int retval;
! task_data *task;
! /* validate task ID */
! if ((task_id < 0) || (task_id >= RTAPI_MAX_TASKS)) {
! return RTAPI_BADID;
}
! /* point to the task's data */
! task = &(task_array[task_id]);
! /* check task status */
! if (task->state == EMPTY) {
! /* nothing to delete */
return RTAPI_INVAL;
}
! if ((task->state == PERIODIC ) || (task->state == FREERUN)) {
! /* task is running, need to stop it */
rtapi_print_msg(RTAPI_MSG_WARN,
! "RTAPI: WARNING: tried to delete task %d while running\n",
! task_id);
! rtapi_task_pause(task_id);
}
! /* get rid of it */
! retval = rt_task_delete(task->ostask);
! if (retval != 0) {
! return RTAPI_FAIL;
! }
! /* free kernel memory */
! kfree(task->ostask);
! /* update data */
! task->state = EMPTY;
task_usage_count--;
/* done */
! rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: delete_task id: %d, count: %d\n",
! task_id, task_usage_count);
return RTAPI_SUCCESS;
}
! int rtapi_task_start(int task_id,
unsigned long int period_nsec,
! unsigned long long when)
{
int retval;
+ task_data *task;
! /* validate task ID */
! if ((task_id < 0) || (task_id >= RTAPI_MAX_TASKS)) {
! return RTAPI_BADID;
}
! /* point to the task's data */
! task = &(task_array[task_id]);
! /* is task ready to be started? */
! if (task->state != PAUSED) {
return RTAPI_INVAL;
}
! if (when == RTAPI_NOW) {
! /* start the task immediately */
! retval = rt_task_make_periodic(task->ostask, rt_get_time(),
! nano2count((RTIME) period_nsec));
! if (retval != 0) {
! return RTAPI_FAIL;
}
} else {
! /* schedule the task to start when requested */
! retval = rt_task_make_periodic(task->ostask,
! nano2count((RTIME) when),
! nano2count((RTIME) period_nsec));
if (retval != 0) {
return RTAPI_FAIL;
}
+ /* check to see if we got done in time */
+ if (rt_get_time() > nano2count((RTIME) when)) {
+ retval = RTAPI_LATE;
+ }
}
! /* ok, task is started (or at least scheduled to start) */
! task->state = PERIODIC;
! rtapi_print_msg(RTAPI_MSG_INFO, "RTAPI: start_task id: %d\n", task_id);
return retval;
}
! int rtapi_wait(void)
{
! rt_task_wait_period();
return RTAPI_SUCCESS;
}
! int rtapi_task_resume(int task_id)
{
int retval;
+ task_data *task;
! /* validate task ID */
! if ((task_id < 0) || (task_id >= RTAPI_MAX_TASKS)) {
! return RTAPI_BADID;
}
! /* point to the task's data */
! task = &(task_array[task_id]);
! /* is task ready to be started? */
! if (task->state != PAUSED) {
! return RTAPI_INVAL;
}
! /* start the task */
! retval = rt_task_resume(task->ostask);
if (retval != 0) {
return RTAPI_FAIL;
}
+ /* update task data */
+ task->state = FREERUN;
return RTAPI_SUCCESS;
}
! int rtapi_task_pause(int task_id)
{
int retval;
+ task_data *task;
! /* validate task ID */
! if ((task_id < 0) || (task_id >= RTAPI_MAX_TASKS)) {
! return RTAPI_BADID;
}
! /* point to the task's data */
! task = &(task_array[task_id]);
! /* is it running? */
! if ((task->state != PERIODIC ) && (task->state != FREERUN)) {
! return RTAPI_INVAL;
}
! retval = rt_task_suspend(task->ostask);
if (retval != 0) {
return RTAPI_FAIL;
}
+ /* update task data */
+ task->state = PAUSED;
return RTAPI_SUCCESS;
}
! int rtapi_task_self(void)
{
RT_TASK *ptr;
int n;
/* ask OS for pointer to its data for the current task */
ptr = rt_whoami();
***************
*** 685,698 ****
n = 0;
while (n < RTAPI_MAX_TASKS) {
! if (task_array[n] != NULL) {
! if (&(task_array[n]->ostask) == ptr) {
! /* found a match */
! *taskptr = task_array[n];
! return RTAPI_SUCCESS;
! }
}
n++;
}
! return RTAPI_INVAL;
}
--- 757,767 ----
n = 0;
while (n < RTAPI_MAX_TASKS) {
! if (task_array[n].ostask == ptr) {
! /* found a match */
! return n;
}
n++;
}
! return RTAPI_FAIL;
}
Index: rtapi.h
===================================================================
RCS file: /cvsroot/emc/rtapi/src/rtapi/rtapi.h,v
retrieving revision 1.18
retrieving revision 1.19
diff -C2 -d -r1.18 -r1.19
*** rtapi.h 11 Aug 2003 19:17:06 -0000 1.18
--- rtapi.h 13 Aug 2003 05:55:07 -0000 1.19
***************
*** 46,57 ****
#define RTAPI_SUCCESS 0 /* call successfull */
#define RTAPI_UNSUP -1 /* function not supported */
#define RTAPI_BADH -2 /* bad task, shmem, sem, or fifo handle */
#define RTAPI_INVAL -3 /* invalid argument */
#define RTAPI_NOMEM -4 /* not enough memory */
! #define RTAPI_PERM -5 /* permission denied */
! #define RTAPI_BUSY -6 /* resource is busy or locked */
! #define RTAPI_NOTFND -7 /* object not found */
! #define RTAPI_FAIL -8 /* operation failed */
! #define RTAPI_LATE -9 /* task could not start when requested */
/* NOTE: RTAPI assumes that ints are at least 32 bits long */
--- 46,60 ----
#define RTAPI_SUCCESS 0 /* call successfull */
#define RTAPI_UNSUP -1 /* function not supported */
+ #define RTAPI_BADID -2 /* bad task, shmem, sem, or fifo ID */
+ /* FIXME - remove BADH once everything is converted over to IDs */
#define RTAPI_BADH -2 /* bad task, shmem, sem, or fifo handle */
#define RTAPI_INVAL -3 /* invalid argument */
#define RTAPI_NOMEM -4 /* not enough memory */
! #define RTAPI_LIMIT -5 /* resource limit reached */
! #define RTAPI_PERM -6 /* permission denied */
! #define RTAPI_BUSY -7 /* resource is busy or locked */
! #define RTAPI_NOTFND -8 /* object not found */
! #define RTAPI_FAIL -9 /* operation failed */
! #define RTAPI_LATE -10 /* task could not start when requested */
/* NOTE: RTAPI assumes that ints are at least 32 bits long */
***************
*** 61,65 ****
* In fact, don't even count on handles always being pointers. */
! typedef struct rtapi_task *rtapi_task_handle;
typedef struct rtapi_shmem *rtapi_shmem_handle;
typedef struct rtapi_sem *rtapi_sem_handle;
--- 64,69 ----
* In fact, don't even count on handles always being pointers. */
! /* SEE, it's happening... tasks are now referred to by int task id's */
! /* the others will change soon */
typedef struct rtapi_shmem *rtapi_shmem_handle;
typedef struct rtapi_sem *rtapi_sem_handle;
***************
*** 149,152 ****
--- 153,161 ----
************************************************************************/
+ /* NOTE: The RTAPI is designed to be a _simple_ API. As such, it uses *
+ * a very simple strategy to deal with SMP systems. It ignores them! *
+ * All tasks are scheduled on the first CPU. That doesn't mean that *
+ * additional CPUs are wasted, they will be used for non-realtime code. */
+
/** The 'rtapi_prio_xxxx()' functions provide a portable way to set *
* task priority. The mapping of actual priority to priority number *
***************
*** 169,267 ****
! /** 'rtapi_task_new()' is the first step in creating a task. Allocs *
! * and initializes internal rtapi and rtos data related to the task. *
! * Returns a status code. On success, '*taskptr' becomes a handle *
! * which points to the internal task data. This handle is used for all *
! * subsequent calls that need to act on the task. */
! extern int rtapi_task_new(rtapi_task_handle * taskptr);
! /** 'rtapi_task_delete()' is the counterpart to 'rtapi_task_new()'. *
* It frees memory associated with 'task', and does any other cleanup *
! * needed. If the task has been started, you must stop it before *
! * deleting it, or bad things might happen. Returns a status code. *
! * Call from within module cleanup code or any other task. A task *
! * should not attempt to delete itself! */
! extern int rtapi_task_delete(rtapi_task_handle task);
! /** 'rtapi_task_start()' does the bulk of the work needed to create *
! * and run a realtime task. 'task' is a task handle from a call to *
! * rtapi_task_new(). 'taskcode' is the name of a function taking one *
! * int and returning void, which contains the task code. 'arg' will be *
! * passed to 'taskcode' as an abitrary int value when the task is *
! * invoked. 'prio' is the priority, as determined by one of the *
! * priority functions above. *
! * 'stacksize' is the amount of stack to be reserved for the task - be *
! * generous, hardware interrupts may use the same stack. *
* 'period_nsec' is the task period in nanoseconds, which will be *
! * rounded to the nearest multiple of the global clock period. If *
! * 'period_nsec' is zero, the task is assumed to be in a paused state *
! * and will be resumed immediately. rtapi_task_resume() would be the *
! * prefered method of restarting a paused task. *
! * 'when' is the desired start time for the task. If RTAPI_NOW, the *
! * task will start immediately. Otherwise, the task will be scheduled *
! * to start at the appropriate time. If the RTOS doesn't support *
! * starting tasks at a specific time, it will return RTAPI_UNSUP and *
! * the task will not be started. Otherwise, the task will be scheduled *
! * to start at the desired time. If the desired time has already *
! * passed, the task will start immediately, and function will return *
! * RTAPI_LATE. Be advised that some RTOSs may execute the task once as *
! * soon as it is scheduled, even if it is not to start until some time *
! * in the future. Tasks should use flags or another mechanism to *
! * prevent them from doing anything prematurely. 'when' uses time as *
! * returned by rtapi_get_time(). *
! * If non-zero, 'uses_fp' tells the OS that the task uses floating *
! * point so it can save the FPU registers on a task switch. Failing *
! * to save registers when needed causes the dreaded "NAN bug", so most *
! * tasks should set 'uses_fp' to 1. If a task definitely does not use *
! * floating point, setting 'uses_fp' to zero saves a few microseconds *
! * per task switch. Returns a status code. Call from module init code *
! * (preferred) or within a realtime task. May block. */
- #define RTAPI_NO_FP 0
- #define RTAPI_USES_FP 1
#define RTAPI_NOW 0
! extern int rtapi_task_start(rtapi_task_handle task,
! void (*taskcode) (int),
! int arg, int prio,
! unsigned long int stacksize,
unsigned long int period_nsec,
! unsigned long long when, unsigned char uses_fp);
! /** 'rtapi_task_stop()' is the counterpart to 'rtapi_task_start()'. *
! * Permanently stops 'task', and prepares it to be deleted. Returns *
! * a status code. Call from within module cleanup code or any other *
! * task - a task should not attempt to stop itself! */
! extern int rtapi_task_stop(rtapi_task_handle task);
! /** 'rtapi_task_pause() causes 'task' to temporarily stop execution. *
! * It will resume when 'rtapi_task_resume()' is called with the same *
! * task handle. A task can pause itself, but obviously cannot resume *
! * itself. Returns a status code. */
! extern int rtapi_task_pause(rtapi_task_handle task);
! extern int rtapi_task_resume(rtapi_task_handle task);
! /** 'rtapi_wait()' suspends execution of the current task until the *
! * next period. At the beginning of the next period, execution will *
! * resume immediately after the call to 'rtapi_wait()', instead of at *
! * beginning of the 'taskcode' function. Call only from a task. *
! * Returns a status code. */
! extern int rtapi_wait(void);
! /** 'rtapi_task_get_handle()' sets '*taskptr' equal to the handle of */
! /* the current task. Call only from a task. Returns a status code. */
- extern int rtapi_task_get_handle(rtapi_task_handle * taskptr);
--- 178,278 ----
! /** 'rtapi_task_new()' creates but does not start a realtime task. *
! * The task is created in the "paused" state. To start the task, call *
! * either rtapi_task_start() for periodic tasks, or rtapi_task_resume() *
! * for free-running tasks. *
! * On success, returns a non-negative integer task ID. This ID is used *
! * for all subsequent calls that need to act on the task. On failure, *
! * returns a negative error code as listed above. *
! * 'taskcode' is the name of a function taking one int and returning *
! * void, which contains the task code. 'arg' will be passed to *
! * 'taskcode' as an abitrary int value when the task is started. *
! * 'prio' is the priority, as determined by one of the priority *
! * functions above. 'stacksize' is the amount of stack to be reserved *
! * for the task - be generous, hardware interrupts may use the same *
! * stack. 'uses_fp' is a flag that tells the OS whether the task uses *
! * floating point so it can save the FPU registers on a task switch. *
! * Failing to save registers when needed causes the dreaded "NAN bug", *
! * so most tasks should set 'uses_fp' to RTAPI_USES_FP. If a task *
! * definitely does not use floating point, setting 'uses_fp' to *
! * RTAPI_NO_FP saves a few microseconds per task switch. */
! #define RTAPI_NO_FP 0
! #define RTAPI_USES_FP 1
+ extern int rtapi_task_new(void (*taskcode) (int),
+ int arg, int prio,
+ unsigned long int stacksize,
+ int uses_fp);
!
! /** 'rtapi_task_delete()' is deletes a task. 'task_id' is a task ID *
! * from a previous call to rtapi_task_new(). *
* It frees memory associated with 'task', and does any other cleanup *
! * needed. If the task has been started, you should pause it before *
! * deleting it. Returns a status code. Call from within init or *
! * cleanup code, or from another task. A task cannot delete itself! */
! extern int rtapi_task_delete(int task_id);
! /** 'rtapi_task_start()' starts a task in periodic mode. 'task_id' is *
! * a task ID from a call to rtapi_task_new(). The task must be in *
! * the "paused" state, or it will return RTAPI_INVAL. *
* 'period_nsec' is the task period in nanoseconds, which will be *
! * rounded to the nearest multiple of the global clock period. A task *
! * period less than the clock period (including zero) will be set equal *
! * to the clock period. *
! * If 'when' is RTAPI_NOW, the task will start immediately. Otherwise, *
! * 'when' is assumed to be the desired start time, using the same time- *
! * base as rtapi_get_time(). The task will be scheduled to start at *
! * the desired time. If the desired time has already passed, the task *
! * will start immediately, and function will return RTAPI_LATE. If *
! * 'when' is not RTAPI_NOW, and the RTOS doesn't support starting tasks *
! * at a specific time, it will return RTAPI_UNSUP and the task will not *
! * be started. */
#define RTAPI_NOW 0
! extern int rtapi_task_start(int task_id,
unsigned long int period_nsec,
! unsigned long long when);
! /** 'rtapi_wait()' suspends execution of the current task until the *
! * next period. The task must be periodic, if not, the result is *
! * undefined. The function will return RTAPI_SUCCESS at the beginning *
! * of the next period. Call only from within a task. */
! extern int rtapi_wait(void);
! /** 'rtapi_task_resume() starts a task in free-running mode. 'task_id' *
! * is a task ID from a call to rtapi_task_new(). The task must be in *
! * the "paused" state, or it will return RTAPI_INVAL. *
! * A free running task runs continuously until either 1) It is prempted *
! * by a higher priority task. It will resume as soon as the higher *
! * priority task releases the CPU. Or 2) It calls a blocking function, *
! * like rtapi_sem_take(). It will resume when the function unblocks. *
! * Or 3) it is returned to the "paused" state by rtapi_task_pause(). */
! extern int rtapi_task_resume(int task_id);
! /** 'rtapi_task_pause() causes 'task_id' to stop execution and change *
! * to the "paused" state. 'task_id' can be free-running or periodic. *
! * Note that rtapi_task_pause() may called from any task, or from init *
! * or cleanup code, not just from the task that is to be paused. *
! * The task will resume execution when either rtapi_task_resume() or *
! * rtapi_task_start() is called. */
! extern int rtapi_task_pause(int task_id);
! /** 'rtapi_task_self()' returns the task ID of the current task. *
! * May return a negative error code if called from outside a task. */
!
! extern int rtapi_task_self(void);
|