我建议你在内核中挖掘几种延迟工作的方法(因为这是你最终需要的)。
最接近您明确要求的解决方案是使用
struct task_struct * kthread_create(int (*threadfn) (void *data), void * data, const char namefmt[], ...);
另一种可能适合您的问题的方法是使用工作队列。有了这个,你必须首先声明一个你想要推迟的作品。您可以使用两个预处理器宏来执行此操作,具体取决于您希望分配工作结构的位置:
- 在堆栈上:
DECLARE_WORK(name, void (*func)(void*), void *data); 将使用func 工作函数在堆栈上自动初始化一个struct work_struct,该工作函数将在运行时提供data。
- 在堆上:假设你已经分配了一个
struct work_struct 对象,你只想用你的函数和合适的数据来初始化它。那么你应该使用INIT_WORK(struct work_struct *work, void (*func)(void*), void *data);
当你想让你的任务运行时,你必须安排它,然后它会出现在相关的工作线程中运行的工作列表中工作队列。如果您只想使用默认工作队列,则必须使用以下两个函数之一:
int schedule_work(struct work_struct *work);
int schedule_delayed_work(struct work_struct *work, unsigned long delay);
delay 以 jiffies(处理器时钟的滴答声)表示。
如果您创建了自定义工作队列,则必须使用其他功能。但首先,让我们看看如何创建自己的工作队列对象。为此,您只需调用:
struct workqueue_struct create_workqueue(const char *name);
完成后,您可以使用类似于之前显示的两个功能将待处理的工作添加到队列中。
int queue_work(struct workqueue_struct *wq, struct work_struct *work);
int queue_delayed_work(struct workqueue_struct *wq,
struct work_struct *work, unsigned long delay);
如果你想刷新待处理的作品列表,只需使用:
/* On the default work queue */
void flush_scheduled_work(void);
/* On a dynamically created work queue */
void flush_workqueue(struct workqueue_struct *wq);
请注意,这将记录尚未准备就绪的刷新延迟工作......如果您想取消延迟工作,您必须使用int cancel_delayed_work(struct work_struct *work);。
工作线程的作用如下:
- 虽然要运行的作品列表非空:
- 它抓取列表顶部的工作(
struct work_struct 对象)。
- 它运行对象
func 和对象data,如果工作结构存储在struct work_struct *work 中,它将执行(*work->func)(work->data);
- 如果计划工作列表为空,则进入睡眠状态。当您安排工作时,它将被唤醒。
显然,当您需要始终准备好运行后台任务时,第二个选项不适合。在这种情况下,您需要一个标准的kthread。请参阅我链接的手册页,它非常清楚地解释了如何使用它。
要回答您的问题,您可以运行两个线程。一个发送者和一个接收者。接收器接收到传入的数据包(这可能比看起来更复杂,您可能必须处理irq handlers 才能这样做......)。因此,kthread_create 选项对您有好处。另一方面,您可以有一个下半部分,当您获取要发送的数据(对于发送者)或刚刚收到适当的数据包(收件人)。在这种情况下,您可能必须使用 工作队列 和 tasklet(或 softirqs)。我稍后会编辑我的帖子来描述这些野兽,因为我现在时间不多了。