static int xmit_thread_worker(void *arg);
///////////////////////////////////////////////////////////////////////////////
static struct task_struct *xmit_thread = NULL;
// 等待线程启动与完成
static struct completion start_done;
static struct completion end_done;
// 线程状态
static u32 thread_state = 0x0;
// 终止线程标记
static volatile u32 xmit_stop = 0x0;
// skb发送队列
struct sk_buff_head pkt_xmit;
///////////////////////////////////////////////////////////////////////////////
int xmit_thread_init(void)
{
int rc = 0x0;
// 初始化队列与completion
skb_queue_head_init( &pkt_xmit );
init_completion( &start_done );
init_completion( &end_done );
// 创建线程
xmit_thread = kthread_create( xmit_thread_worker, NULL, " ");
if ( IS_ERR( xmit_thread ) ) {
xmit_thread = NULL;
pr_err( "kthread_create occur error.\n" );
rc = -1;
}
else {
pr_emerg( "kthread_create success.\n" );
// 唤醒线程
wake_up_process( xmit_thread );
// 等待线程启动完成
wait_for_completion( &start_done );
pr_emerg( "xmit thread worker run success.\n" );
}
return rc;
}
// skb入队列发送
void xmit_enqueue( struct sk_buff *skb )
{
// skb 入队列
skb_queue_tail( &pkt_xmit, skb );
if ( NULL != xmit_thread ){
// 唤醒线程
wake_up_process( xmit_thread );
}
}
// 销毁线程
void xmit_thread_fini(void)
{
struct sk_buff *skb = NULL;
pr_emerg( "wait for xmit thread done\n" );
if ( NULL == xmit_thread ){
return ;
}
// 设置线程终止标记
xmit_stop = 0x1;
// 等待完成
wait_for_completion( &end_done );
// 释放队列中未发送skb
do {
skb = __skb_dequeue( &pkt_xmit );
if ( NULL != skb ) {
kfree_skb( skb );
}
}while( NULL != skb );
}
static int xmit_thread_worker(void *arg)
{
struct sk_buff *skb = NULL;
// 通知启动完成
complete( &start_done );
while( 1 ) {
thread_state = 0x0;
// 调度
schedule_timeout_interruptible(2);
//__set_current_state(TASK_RUNNING);
thread_state = 0x1;
// 是否终止?
if ( xmit_stop ) {
pr_emerg( "%s end.\n", __func__ );
break;
}
do {
// 取skb发送队列并发送
skb = skb_dequeue( &pkt_xmit );
if ( NULL != skb ) {
dev_queue_xmit( skb );
}
// 是否终止?
if ( xmit_stop ) {
pr_emerg( "%s end.\n", __func__ );
goto _out;
}
}while( NULL != skb );
};
_out:
// 通知线程终止
complete( &end_done );
return 0;
}