Linux: Added preliminary work queue support

Based on NuttX work queue code.

Not yet functional.

Signed-off-by: Mark Charlebois <charlebm@gmail.com>
This commit is contained in:
Mark Charlebois 2015-03-25 10:53:08 -07:00
parent 056d5f9075
commit aedf6fe628
9 changed files with 95 additions and 129 deletions

View File

@ -38,6 +38,9 @@
SRCS = \ SRCS = \
px4_linux_impl.cpp \ px4_linux_impl.cpp \
px4_linux_tasks.c \ px4_linux_tasks.c \
work_thread.c \
work_queue.c \
work_cancel.c \
lib_crc32.c \ lib_crc32.c \
drv_hrt.c \ drv_hrt.c \
queue.c \ queue.c \
@ -45,6 +48,7 @@ SRCS = \
dq_remfirst.c \ dq_remfirst.c \
sq_addlast.c \ sq_addlast.c \
sq_remfirst.c \ sq_remfirst.c \
sq_addafter.c sq_addafter.c \
dq_rem.c
MAXOPTIMIZATION = -Os MAXOPTIMIZATION = -Os

View File

@ -56,60 +56,32 @@ long PX4_TICKS_PER_SEC = sysconf(_SC_CLK_TCK);
__END_DECLS __END_DECLS
extern struct wqueue_s gwork[NWORKERS];
namespace px4 namespace px4
{ {
void init(int argc, char *argv[], const char *app_name) void init(int argc, char *argv[], const char *app_name)
{ {
struct param_info_s test_1 = {
"TEST_1",
PARAM_TYPE_INT32
};
test_1.val.i = 2;
struct param_info_s test_2 = {
"TEST_2",
PARAM_TYPE_INT32
};
test_2.val.i = 4;
struct param_info_s rc_x = {
"RC_X",
PARAM_TYPE_INT32
};
rc_x.val.i = 8;
struct param_info_s rc2_x = {
"RC2_X",
PARAM_TYPE_INT32
};
rc2_x.val.i = 16;
param_array[0] = test_1;
param_array[1] = test_2;
param_array[2] = rc_x;
param_array[3] = rc2_x;
param_info_base = (struct param_info_s *) &param_array[0];
param_info_limit = (struct param_info_s *) &param_array[4]; // needs to point at the end of the data,
// therefore number of params + 1
printf("App name: %s\n", app_name); printf("App name: %s\n", app_name);
// Create high priority worker thread
g_work[HPWORK].pid = px4_task_spawn_cmd("wkr_high",
SCHED_DEFAULT,
SCHED_PRIORITY_MAX,
2000,
work_hpthread,
(char* const*)NULL);
// Create low priority worker thread
g_work[LPWORK].pid = px4_task_spawn_cmd("wkr_low",
SCHED_DEFAULT,
SCHED_PRIORITY_MIN,
2000,
work_lpthread,
(char* const*)NULL);
} }
} }
int work_queue(int qid, struct work_s *work, worker_t worker, void *arg, uint32_t delay)
{
printf("work_queue: UNIMPLEMENTED\n");
return PX4_OK;
}
int work_cancel(int qid, struct work_s *work)
{
printf("work_cancel: UNIMPLEMENTED\n");
return PX4_OK;
}

View File

@ -37,15 +37,10 @@
* Included Files * Included Files
****************************************************************************/ ****************************************************************************/
#include <nuttx/config.h> #include <px4_config.h>
#include <px4_defines.h>
#include <queue.h> #include <queue.h>
#include <assert.h> #include <px4_workqueue.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/wqueue.h>
#ifdef CONFIG_SCHED_WORKQUEUE #ifdef CONFIG_SCHED_WORKQUEUE
@ -90,25 +85,25 @@
* *
****************************************************************************/ ****************************************************************************/
int work_cancel(int qid, FAR struct work_s *work) int work_cancel(int qid, struct work_s *work)
{ {
FAR struct wqueue_s *wqueue = &g_work[qid]; struct wqueue_s *wqueue = &g_work[qid];
irqstate_t flags; //irqstate_t flags;
DEBUGASSERT(work != NULL && (unsigned)qid < NWORKERS); //DEBUGASSERT(work != NULL && (unsigned)qid < NWORKERS);
/* Cancelling the work is simply a matter of removing the work structure /* Cancelling the work is simply a matter of removing the work structure
* from the work queue. This must be done with interrupts disabled because * from the work queue. This must be done with interrupts disabled because
* new work is typically added to the work queue from interrupt handlers. * new work is typically added to the work queue from interrupt handlers.
*/ */
flags = irqsave(); //flags = irqsave();
if (work->worker != NULL) if (work->worker != NULL)
{ {
/* A little test of the integrity of the work queue */ /* A little test of the integrity of the work queue */
DEBUGASSERT(work->dq.flink ||(FAR dq_entry_t *)work == wqueue->q.tail); //DEBUGASSERT(work->dq.flink ||(FAR dq_entry_t *)work == wqueue->q.tail);
DEBUGASSERT(work->dq.blink ||(FAR dq_entry_t *)work == wqueue->q.head); //DEBUGASSERT(work->dq.blink ||(FAR dq_entry_t *)work == wqueue->q.head);
/* Remove the entry from the work queue and make sure that it is /* Remove the entry from the work queue and make sure that it is
* mark as availalbe (i.e., the worker field is nullified). * mark as availalbe (i.e., the worker field is nullified).
@ -118,8 +113,8 @@ int work_cancel(int qid, FAR struct work_s *work)
work->worker = NULL; work->worker = NULL;
} }
irqrestore(flags); //irqrestore(flags);
return OK; return PX4_OK;
} }
#endif /* CONFIG_SCHED_WORKQUEUE */ #endif /* CONFIG_SCHED_WORKQUEUE */

View File

@ -37,17 +37,13 @@
* Included Files * Included Files
****************************************************************************/ ****************************************************************************/
#include <nuttx/config.h> #include <px4_config.h>
#include <px4_defines.h>
#include <signal.h>
#include <stdint.h> #include <stdint.h>
#include <queue.h> #include <queue.h>
#include <assert.h> #include <px4_workqueue.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/clock.h>
#include <nuttx/wqueue.h>
#ifdef CONFIG_SCHED_WORKQUEUE #ifdef CONFIG_SCHED_WORKQUEUE
@ -104,13 +100,11 @@
* *
****************************************************************************/ ****************************************************************************/
int work_queue(int qid, FAR struct work_s *work, worker_t worker, int work_queue(int qid, struct work_s *work, worker_t worker, void *arg, uint32_t delay)
FAR void *arg, uint32_t delay)
{ {
FAR struct wqueue_s *wqueue = &g_work[qid]; struct wqueue_s *wqueue = &g_work[qid];
irqstate_t flags;
DEBUGASSERT(work != NULL && (unsigned)qid < NWORKERS); //DEBUGASSERT(work != NULL && (unsigned)qid < NWORKERS);
/* First, initialize the work structure */ /* First, initialize the work structure */
@ -123,14 +117,14 @@ int work_queue(int qid, FAR struct work_s *work, worker_t worker,
* from with task logic or interrupt handlers. * from with task logic or interrupt handlers.
*/ */
flags = irqsave(); //flags = irqsave();
work->qtime = clock_systimer(); /* Time work queued */ work->qtime = clock_systimer(); /* Time work queued */
dq_addlast((FAR dq_entry_t *)work, &wqueue->q); dq_addlast((dq_entry_t *)work, &wqueue->q);
kill(wqueue->pid, SIGWORK); /* Wake up the worker thread */ pthread_kill(wqueue->pid, SIGUSR1); /* Wake up the worker thread */
irqrestore(flags); //irqrestore(flags);
return OK; return PX4_OK;
} }
#endif /* CONFIG_SCHED_WORKQUEUE */ #endif /* CONFIG_SCHED_WORKQUEUE */

View File

@ -37,19 +37,12 @@
* Included Files * Included Files
****************************************************************************/ ****************************************************************************/
#include <nuttx/config.h> #include <px4_config.h>
#include <px4_defines.h>
#include <stdint.h> #include <stdint.h>
#include <unistd.h> #include <unistd.h>
#include <queue.h> #include <queue.h>
#include <assert.h> #include <px4_workqueue.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/wqueue.h>
#include <nuttx/clock.h>
#include <nuttx/kmalloc.h>
#ifdef CONFIG_SCHED_WORKQUEUE #ifdef CONFIG_SCHED_WORKQUEUE
@ -66,29 +59,8 @@
****************************************************************************/ ****************************************************************************/
/* The state of each work queue. */ /* The state of each work queue. */
#ifdef CONFIG_NUTTX_KERNEL
/* Play some games in the kernel mode build to assure that different
* naming is used for the global work queue data structures. This may
* not be necessary but it safer.
*
* In this case g_work is #define'd to be either g_kernelwork or
* g_usrwork in include/nuttx/wqueue.h
*/
# ifdef __KERNEL__
struct wqueue_s g_kernelwork[NWORKERS];
# else
struct wqueue_s g_usrwork[NWORKERS];
# endif
#else /* CONFIG_NUTTX_KERNEL */
struct wqueue_s g_work[NWORKERS]; struct wqueue_s g_work[NWORKERS];
#endif /* CONFIG_NUTTX_KERNEL */
/**************************************************************************** /****************************************************************************
* Private Variables * Private Variables
****************************************************************************/ ****************************************************************************/
@ -115,7 +87,7 @@ static void work_process(FAR struct wqueue_s *wqueue)
{ {
volatile FAR struct work_s *work; volatile FAR struct work_s *work;
worker_t worker; worker_t worker;
irqstate_t flags; //irqstate_t flags;
FAR void *arg; FAR void *arg;
uint32_t elapsed; uint32_t elapsed;
uint32_t remaining; uint32_t remaining;
@ -125,8 +97,9 @@ static void work_process(FAR struct wqueue_s *wqueue)
* we process items in the work list. * we process items in the work list.
*/ */
next = CONFIG_SCHED_WORKPERIOD / USEC_PER_TICK; //next = CONFIG_SCHED_WORKPERIOD / USEC_PER_TICK;
flags = irqsave(); next = 100;
//flags = irqsave();
work = (FAR struct work_s *)wqueue->q.head; work = (FAR struct work_s *)wqueue->q.head;
while (work) while (work)
{ {
@ -158,7 +131,7 @@ static void work_process(FAR struct wqueue_s *wqueue)
* performed... we don't have any idea how long that will take! * performed... we don't have any idea how long that will take!
*/ */
irqrestore(flags); //irqrestore(flags);
worker(arg); worker(arg);
/* Now, unfortunately, since we re-enabled interrupts we don't /* Now, unfortunately, since we re-enabled interrupts we don't
@ -166,7 +139,7 @@ static void work_process(FAR struct wqueue_s *wqueue)
* back at the head of the list. * back at the head of the list.
*/ */
flags = irqsave(); //flags = irqsave();
work = (FAR struct work_s *)wqueue->q.head; work = (FAR struct work_s *)wqueue->q.head;
} }
else else
@ -195,7 +168,7 @@ static void work_process(FAR struct wqueue_s *wqueue)
*/ */
usleep(next * USEC_PER_TICK); usleep(next * USEC_PER_TICK);
irqrestore(flags); //irqrestore(flags);
} }
/**************************************************************************** /****************************************************************************
@ -258,7 +231,7 @@ int work_hpthread(int argc, char *argv[])
work_process(&g_work[HPWORK]); work_process(&g_work[HPWORK]);
} }
return OK; /* To keep some compilers happy */ return PX4_OK; /* To keep some compilers happy */
} }
#ifdef CONFIG_SCHED_LPWORK #ifdef CONFIG_SCHED_LPWORK
@ -276,7 +249,7 @@ int work_lpthread(int argc, char *argv[])
* the IDLE thread (at a very, very low priority). * the IDLE thread (at a very, very low priority).
*/ */
sched_garbagecollection(); //sched_garbagecollection();
/* Then process queued work. We need to keep interrupts disabled while /* Then process queued work. We need to keep interrupts disabled while
* we process items in the work list. * we process items in the work list.
@ -285,7 +258,7 @@ int work_lpthread(int argc, char *argv[])
work_process(&g_work[LPWORK]); work_process(&g_work[LPWORK]);
} }
return OK; /* To keep some compilers happy */ return PX4_OK; /* To keep some compilers happy */
} }
#endif /* CONFIG_SCHED_LPWORK */ #endif /* CONFIG_SCHED_LPWORK */
@ -306,9 +279,13 @@ int work_usrthread(int argc, char *argv[])
work_process(&g_work[USRWORK]); work_process(&g_work[USRWORK]);
} }
return OK; /* To keep some compilers happy */ return PX4_OK; /* To keep some compilers happy */
} }
#endif /* CONFIG_SCHED_USRWORK */ #endif /* CONFIG_SCHED_USRWORK */
int clock_systimer()
{
return 1;
}
#endif /* CONFIG_SCHED_WORKQUEUE */ #endif /* CONFIG_SCHED_WORKQUEUE */

View File

@ -44,6 +44,9 @@
#include <px4_config.h> #include <px4_config.h>
#elif defined (__PX4_LINUX) #elif defined (__PX4_LINUX)
#define CONFIG_NFILE_STREAMS 1 #define CONFIG_NFILE_STREAMS 1
#define CONFIG_SCHED_WORKQUEUE 1
#define CONFIG_SCHED_HPWORK 1
#define CONFIG_SCHED_LPWORK 1
#define CONFIG_ARCH_BOARD_LINUXTEST 1 #define CONFIG_ARCH_BOARD_LINUXTEST 1
#define px4_errx(x, ...) errx(x, __VA_ARGS__) #define px4_errx(x, ...) errx(x, __VA_ARGS__)

View File

@ -123,7 +123,8 @@ __BEGIN_DECLS
extern long PX4_TICKS_PER_SEC; extern long PX4_TICKS_PER_SEC;
__END_DECLS __END_DECLS
#define USEC2TICK(x) (PX4_TICKS_PER_SEC*(long)x/1000000L) #define USEC2TICK(x) (PX4_TICKS_PER_SEC*(long)(x)/1000000L)
#define USEC_PER_TICK (1000000L/PX4_TICKS_PER_SEC)
#define px4_statfs_buf_f_bavail_t unsigned long #define px4_statfs_buf_f_bavail_t unsigned long

View File

@ -55,6 +55,7 @@ typedef int px4_task_t;
#define SCHED_DEFAULT SCHED_FIFO #define SCHED_DEFAULT SCHED_FIFO
#define SCHED_PRIORITY_MAX sched_get_priority_max(SCHED_FIFO) #define SCHED_PRIORITY_MAX sched_get_priority_max(SCHED_FIFO)
#define SCHED_PRIORITY_MIN sched_get_priority_min(SCHED_FIFO)
#define SCHED_PRIORITY_DEFAULT sched_get_priority_max(SCHED_FIFO) #define SCHED_PRIORITY_DEFAULT sched_get_priority_max(SCHED_FIFO)
typedef pthread_t px4_task_t; typedef pthread_t px4_task_t;

View File

@ -43,10 +43,22 @@
#include <nuttx/clock.h> #include <nuttx/clock.h>
#elif defined(__PX4_LINUX) #elif defined(__PX4_LINUX)
#include <stdint.h>
#include <queue.h> #include <queue.h>
__BEGIN_DECLS
#define HPWORK 0
#define LPWORK 1 #define LPWORK 1
#define HPWORK 2 #define NWORKERS 2
struct wqueue_s
{
pid_t pid; /* The task ID of the worker thread */
struct dq_queue_s q; /* The queue of pending work */
};
extern struct wqueue_s g_work[NWORKERS];
/* Defines the work callback */ /* Defines the work callback */
@ -90,8 +102,7 @@ struct work_s
* *
****************************************************************************/ ****************************************************************************/
int work_queue(int qid, FAR struct work_s *work, worker_t worker, int work_queue(int qid, struct work_s *work, worker_t worker, void *arg, uint32_t delay);
FAR void *arg, uint32_t delay);
/**************************************************************************** /****************************************************************************
* Name: work_cancel * Name: work_cancel
@ -110,7 +121,15 @@ int work_queue(int qid, FAR struct work_s *work, worker_t worker,
* *
****************************************************************************/ ****************************************************************************/
int work_cancel(int qid, FAR struct work_s *work); int work_cancel(int qid, struct work_s *work);
int clock_systimer(void);
int work_hpthread(int argc, char *argv[]);
int work_lpthread(int argc, char *argv[]);
__END_DECLS
#else #else
#error "Unknown target OS" #error "Unknown target OS"
#endif #endif