204 lines
6.5 KiB
C
204 lines
6.5 KiB
C
/*
|
|
* \brief Linux kernel API
|
|
* \author Norman Feske
|
|
* \author Sebastian Sumpf
|
|
* \author Josef Soentgen
|
|
* \date 2014-08-21
|
|
*
|
|
* Based on the prototypes found in the Linux kernel's 'include/'.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2014 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU General Public License version 2.
|
|
*/
|
|
|
|
/***********************
|
|
** linux/workqueue.h **
|
|
***********************/
|
|
|
|
enum {
|
|
WQ_MEM_RECLAIM,
|
|
WQ_CPU_INTENSIVE,
|
|
};
|
|
|
|
struct work_struct;
|
|
typedef void (*work_func_t)(struct work_struct *work);
|
|
|
|
struct work_struct {
|
|
atomic_long_t data;
|
|
work_func_t func;
|
|
struct list_head entry;
|
|
};
|
|
|
|
struct delayed_work {
|
|
struct timer_list timer;
|
|
struct work_struct work;
|
|
};
|
|
|
|
bool cancel_work_sync(struct work_struct *work);
|
|
bool cancel_delayed_work_sync(struct delayed_work *work);
|
|
bool cancel_delayed_work(struct delayed_work *dwork);
|
|
int schedule_delayed_work(struct delayed_work *work, unsigned long delay);
|
|
int schedule_work(struct work_struct *work);
|
|
void flush_scheduled_work(void);
|
|
|
|
bool flush_work(struct work_struct *work);
|
|
bool flush_work_sync(struct work_struct *work);
|
|
|
|
|
|
#define PREPARE_WORK(_work, _func) \
|
|
do { (_work)->func = (_func); } while (0)
|
|
|
|
#define PREPARE_DELAYED_WORK(_work, _func) \
|
|
PREPARE_WORK(&(_work)->work, (_func))
|
|
|
|
#define __INIT_WORK(_work, _func, on_stack) \
|
|
do { \
|
|
INIT_LIST_HEAD(&(_work)->entry); \
|
|
PREPARE_WORK((_work), (_func)); \
|
|
} while (0)
|
|
|
|
#define INIT_WORK(_work, _func)\
|
|
do { __INIT_WORK((_work), (_func), 0); } while (0)
|
|
|
|
#define INIT_DELAYED_WORK(_work, _func) \
|
|
do { \
|
|
INIT_WORK(&(_work)->work, (_func)); \
|
|
init_timer(&(_work)->timer); \
|
|
} while (0)
|
|
|
|
|
|
/* dummy for queue_delayed_work call in storage/usb.c */
|
|
#define system_freezable_wq 0
|
|
struct workqueue_struct { unsigned unused; };
|
|
|
|
struct workqueue_struct *create_singlethread_workqueue(const char *name);
|
|
struct workqueue_struct *alloc_ordered_workqueue(const char *fmt, unsigned int flags, ...) __printf(1, 3);
|
|
struct workqueue_struct *alloc_workqueue(const char *fmt, unsigned int flags,
|
|
int max_active, ...) __printf(1, 4);
|
|
void destroy_workqueue(struct workqueue_struct *wq);
|
|
void flush_workqueue(struct workqueue_struct *wq);
|
|
bool queue_delayed_work(struct workqueue_struct *, struct delayed_work *, unsigned long);
|
|
bool flush_delayed_work(struct delayed_work *dwork);
|
|
bool queue_work(struct workqueue_struct *wq, struct work_struct *work);
|
|
|
|
#define DECLARE_DELAYED_WORK(n, f) \
|
|
struct delayed_work n
|
|
|
|
bool mod_delayed_work(struct workqueue_struct *, struct delayed_work *,
|
|
unsigned long);
|
|
|
|
static inline struct delayed_work *to_delayed_work(struct work_struct *work)
|
|
{
|
|
return container_of(work, struct delayed_work, work);
|
|
}
|
|
|
|
extern struct workqueue_struct *system_wq;
|
|
|
|
enum {
|
|
WORK_STRUCT_STATIC = 0,
|
|
|
|
WORK_STRUCT_COLOR_SHIFT = 4,
|
|
WORK_STRUCT_COLOR_BITS = 4,
|
|
WORK_STRUCT_FLAG_BITS = WORK_STRUCT_COLOR_SHIFT + WORK_STRUCT_COLOR_BITS,
|
|
WORK_OFFQ_FLAG_BASE = WORK_STRUCT_FLAG_BITS,
|
|
|
|
WORK_OFFQ_FLAG_BITS = 1,
|
|
WORK_OFFQ_POOL_SHIFT = WORK_OFFQ_FLAG_BASE + WORK_OFFQ_FLAG_BITS,
|
|
WORK_OFFQ_LEFT = BITS_PER_LONG - WORK_OFFQ_POOL_SHIFT,
|
|
WORK_OFFQ_POOL_BITS = WORK_OFFQ_LEFT <= 31 ? WORK_OFFQ_LEFT : 31,
|
|
WORK_OFFQ_POOL_NONE = (1LU << WORK_OFFQ_POOL_BITS) - 1,
|
|
|
|
WORK_STRUCT_NO_POOL = (unsigned long)WORK_OFFQ_POOL_NONE << WORK_OFFQ_POOL_SHIFT,
|
|
};
|
|
|
|
#define WORK_DATA_STATIC_INIT() \
|
|
ATOMIC_LONG_INIT(WORK_STRUCT_NO_POOL | WORK_STRUCT_STATIC)
|
|
|
|
#define __WORK_INIT_LOCKDEP_MAP(n, k)
|
|
|
|
#define __WORK_INITIALIZER(n, f) { \
|
|
.data = WORK_DATA_STATIC_INIT(), \
|
|
.entry = { &(n).entry, &(n).entry }, \
|
|
.func = (f), \
|
|
__WORK_INIT_LOCKDEP_MAP(#n, &(n)) \
|
|
}
|
|
|
|
#define DECLARE_WORK(n, f) \
|
|
struct work_struct n = __WORK_INITIALIZER(n, f)
|
|
|
|
|
|
/******************
|
|
** linux/wait.h **
|
|
******************/
|
|
|
|
typedef struct wait_queue_head { void *list; } wait_queue_head_t;
|
|
typedef struct wait_queue { unsigned unused; } wait_queue_t;
|
|
|
|
#define DEFINE_WAIT(name) \
|
|
wait_queue_t name;
|
|
|
|
#define __WAIT_QUEUE_HEAD_INITIALIZER(name) { 0 }
|
|
|
|
#define DECLARE_WAITQUEUE(name, tsk) \
|
|
wait_queue_t name
|
|
|
|
#define DECLARE_WAIT_QUEUE_HEAD(name) \
|
|
wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
|
|
|
|
#define DEFINE_WAIT_FUNC(name, function) \
|
|
wait_queue_t name
|
|
|
|
/* simplified signature */
|
|
void __wake_up(wait_queue_head_t *q, bool all);
|
|
|
|
#define wake_up(x) __wake_up(x, false)
|
|
#define wake_up_all(x) __wake_up(x, true)
|
|
#define wake_up_interruptible(x) __wake_up(x, false)
|
|
#define wake_up_interruptible_all(x) __wake_up(x, true)
|
|
|
|
void init_waitqueue_head(wait_queue_head_t *);
|
|
int waitqueue_active(wait_queue_head_t *);
|
|
|
|
/* void wake_up_interruptible(wait_queue_head_t *); */
|
|
void wake_up_interruptible_sync_poll(wait_queue_head_t *, int);
|
|
void wake_up_interruptible_poll(wait_queue_head_t *, int);
|
|
|
|
void prepare_to_wait(wait_queue_head_t *, wait_queue_t *, int);
|
|
void prepare_to_wait_exclusive(wait_queue_head_t *, wait_queue_t *, int);
|
|
void finish_wait(wait_queue_head_t *, wait_queue_t *);
|
|
|
|
int autoremove_wake_function(wait_queue_t *, unsigned, int, void *);
|
|
void add_wait_queue(wait_queue_head_t *, wait_queue_t *);
|
|
void add_wait_queue_exclusive(wait_queue_head_t *, wait_queue_t *);
|
|
void remove_wait_queue(wait_queue_head_t *, wait_queue_t *);
|
|
|
|
/* our wait event implementation - it's okay as value */
|
|
void __wait_event(wait_queue_head_t);
|
|
|
|
#define _wait_event(wq, condition) while (!(condition)) { __wait_event(wq); }
|
|
#define wait_event(wq, condition) ({ _wait_event(wq, condition); })
|
|
#define wait_event_interruptible(wq, condition) ({ _wait_event(wq, condition); 0; })
|
|
|
|
#define _wait_event_timeout(wq, condition, timeout) \
|
|
({ int res = 1; \
|
|
prepare_to_wait(&wq, 0, 0); \
|
|
while (1) { \
|
|
if ((condition) || !res) { \
|
|
break; \
|
|
} \
|
|
res = schedule_timeout(jiffies + timeout); \
|
|
} \
|
|
finish_wait(&wq, 0); \
|
|
res; \
|
|
})
|
|
|
|
#define wait_event_timeout(wq, condition, timeout) \
|
|
({ \
|
|
int ret = _wait_event_timeout(wq, (condition), timeout); \
|
|
ret; \
|
|
})
|