Linux Kernel -- chess game

Description

This is an exercise for kernel coding.

Focus on,

  • EXPORT_SYMBOL  //communicate between modules
  • work_queue
  • wait_queue
  • spinlock
  • list

There are 3 modules,  chess.ko, chessplayer0.ko, chessplayer1.ko


References:

http://www.linuxjournal.com/article/6916?page=0,1

http://www.ibm.com/developerworks/linux/library/l-tasklets/index.html

Source files,

chess.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/uaccess.h>
#include <linux/spinlock.h>
#include <linux/sched.h>

#include "chess.h"


MODULE_LICENSE("GPL");

MODULE_AUTHOR("Tico.Feng");

static char chessboard[3][3] = {{' ',' ',' '},{' ',' ',' '},{' ',' ',' '}};
static struct player_list players;
spinlock_t      step_lock=SPIN_LOCK_UNLOCKED;
static DECLARE_WAIT_QUEUE_HEAD(chess_wq0);
static DECLARE_WAIT_QUEUE_HEAD(chess_wq1);
static DECLARE_WAIT_QUEUE_HEAD(game_wq);
static bool ready=false;  //false, not ready, true, ready
//wait_queue_head_t chess_wq0;
//wait_queue_head_t chess_wq1;
EXPORT_SYMBOL(chess_wq0);
EXPORT_SYMBOL(chess_wq1);
EXPORT_SYMBOL(game_wq);


void showchessboard();
bool gameready();

void registerplayer(struct player_list *player) {
        struct player_list *tmp;
        tmp = (struct player_list *)kmalloc(sizeof(struct player_list),GFP_KERNEL);
        tmp->id=player->id;
        tmp->status=player->status;
        tmp->go=player->go;
        tmp->piece=player->piece;
        if(tmp->go == 0) //offensive, bind chess_wq0 for it.
        {
                tmp->wtq = &chess_wq0;
        }else{  // the second partener, bind chess_wq1 for it.
                tmp->wtq = &chess_wq1;
        }
        list_add(&(tmp->list),&(players.list));
        if(gameready())
                wake_up_interruptible(&game_wq);
}

void cleanplayer()
{
        struct player_list *tmp;
        struct list_head *pos, *q;
        list_for_each_safe(pos,q,&players.list){
                tmp = list_entry(pos,struct player_list,list);
                list_del(pos);
                kfree(tmp);
        }
}

EXPORT_SYMBOL(registerplayer);

bool gameready(){
        struct player_list *tmp;
        int num=0;
        list_for_each_entry(tmp,&players.list,list) {
                num++;
        }
        if(num == 2)
                ready = true;
        else
                ready = false;

        return ready;
}
EXPORT_SYMBOL(gameready);

int runonestep(struct player_list *player) {
        int status=0;
        struct player_list *tmp;
        if( player->x >= MAXBOARDX || player->y >= MAXBOARDY ) {
                printk(KERN_INFO"the step out of board.\n");
                return -1;
        }

        spin_lock(&step_lock);
        chessboard[player->x][player->y]=player->piece;
        list_for_each_entry(tmp,&players.list,list) {
                if(tmp->id == player->id){
                        printk(KERN_INFO"player %d finish one step.\n",tmp->id);
                        tmp->status=0;  //finish one step, waiting for...
                }else{
                        printk(KERN_INFO"wake up player %d to go.\n",tmp->id);
                        tmp->status=1; //it turn for opponent to go
                        wake_up_interruptible(tmp->wtq);
                }
        }
        spin_unlock(&step_lock);
        showchessboard();

        return status;
}
EXPORT_SYMBOL(runonestep);

int getplayerstatus(struct player_list *player){
        int status=0;
        struct player_list *tmp;
        list_for_each_entry(tmp,&players.list,list) {
                if(tmp->id == player->id){
                        status = tmp->status;
                        break;
                }
        }
        return status;
}
EXPORT_SYMBOL(getplayerstatus);

void showchessboard() {
        printk(KERN_INFO"     %c | %c | %c\n",chessboard[0][0],chessboard[0][1],chessboard[0][2]);
        printk(KERN_INFO"    -------------\n");
        printk(KERN_INFO"     %c | %c | %c\n",chessboard[1][0],chessboard[1][1],chessboard[1][2]);
        printk(KERN_INFO"    -------------\n");
        printk(KERN_INFO"     %c | %c | %c\n\n\n",chessboard[2][0],chessboard[2][1],chessboard[2][2]);
}

static int __init init_chess(void)
{
        printk(KERN_INFO "init_chess-->\n");
        //struct player_list *tmp;
        INIT_LIST_HEAD(&players.list);
        //init_waitqueue_head(&chess_wq0);
        //init_waitqueue_head(&chess_wq1);

/*
        tmp = (struct player_list *)kmalloc(sizeof(struct player_list),GFP_KERNEL);
        tmp->id=0;
        tmp->status=1;
        tmp->go=0;

        registerplayer(tmp);



        list_for_each_entry(tmp,&players.list,list) {

                printk(KERN_INFO "id=%d\n",tmp->id);
                printk(KERN_INFO "status=%d\n",tmp->status);
                printk(KERN_INFO "go=%d\n",tmp->go);
        }

        showchessboard();
        */
        return 0;

}

module_init(init_chess);

static void __exit exit_chess(void)
{
        printk(KERN_INFO "exit_chess-->\n");
        cleanplayer();
}

module_exit(exit_chess);

chessplayer0.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/uaccess.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/wait.h>
#include <linux/sched.h>

#include "chess.h"


MODULE_LICENSE("GPL");

MODULE_AUTHOR("Tico.Feng");

extern void registerplayer(struct player_list *player);
extern int runonestep(struct player_list *player);
extern int getplayerstatus(struct player_list *player);
extern bool gameready();
extern wait_queue_head_t game_wq;
extern wait_queue_head_t chess_wq0;

static int  tactics[5][2] = { {0,0},{0,2},
                            {1,1},
                            {2,0},{2,2} };
static struct player_list player;
static struct workqueue_struct *wq;


void play(work struct *work) {
        int steps=5;
        int i=0;
        if(!gameready()) {
                    printk(KERN_INFO"game is not ready, waiting for other to join...\n");
                    wait_event_interruptible(game_wq, gameready() );
                    printk(KERN_INFO"Start the game...\n");
        }

        for(i=0;i<steps;i++) {
                /* if offensive, start the first step*/
                if(player.go == 0 && i==0) {
                    player.x=tactics[i][0];
                    player.y=tactics[i][1];
                    runonestep(&player);
                }else{
                    printk(KERN_INFO "player %d going to sleep status=%d.\n",player.id,getplayerstatus(&player));
                    wait_event_interruptible(chess_wq0, getplayerstatus(&player) == 1);
                    printk(KERN_INFO "awken player %d going to play one step.\n",player.id);
                    player.x=tactics[i][0];
                    player.y=tactics[i][1];
                    runonestep(&player);
                }
        }

        work_struct *my_work=work;

        kfree((void *)my_work);

}


static int __init init_chess_player(void)
{
        struct work_struct *chesswork;
        /*init player and register it*/
        player.id=0x00;
        player.status=0; /*ready to go*/
        player.go=0; /*offensize*/
        player.piece='0';
        registerplayer(&player);
/*
        player.x=0;
        player.y=0;

        runonestep(&player);
        */

        wq = create_singlethread_workqueue("my_chess_queue");

        chesswork = kmalloc(sizeof(struct work_struct), GFP_KERNEL);

        /*init the work struct*/
        INIT_WORK(chesswork,play);

        queue_work(wq, chesswork);


        return 0;
}

module_init(init_chess_player);

static void __exit exit_chess_player(void)
{
        flush_workqueue(wq);
        destroy_workqueue(wq);
        printk(KERN_INFO "exit_chess-->\n");
}

module_exit(exit_chess_player);


chessplayer1.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/uaccess.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/wait.h>
#include <linux/sched.h>

#include "chess.h"


MODULE_LICENSE("GPL");

MODULE_AUTHOR("Tico.Feng");

extern void registerplayer(struct player_list *player);
extern int runonestep(struct player_list *player);
extern int getplayerstatus(struct player_list *player);
extern wait_queue_head_t chess_wq1;

static int  tactics[4][2] = { {0,1},{1,0},{1,2},{2,1}};

static struct player_list player;
static struct workqueue_struct *wq;


void play(work_struct *work) {
        int steps=4;
        int i=0;
        for(i=0;i<steps;i++) {
                /* if offensive, start the first step*/
                if(player.go == 0 && i==0) {
                    player.x=tactics[i][0];
                    player.y=tactics[i][1];
                    runonestep(&player);
                }else{
                    printk(KERN_INFO "player %d going to sleep.\n",player.id);
                    wait_event_interruptible(chess_wq1, getplayerstatus(&player) == 1);
                    printk(KERN_INFO "awken player %d going to play one step.\n",player.id);
                    player.x=tactics[i][0];
                    player.y=tactics[i][1];
                    runonestep(&player);
                }

        }

        work_struct *my_work=work;

        kfree((void *)my_work);


}


static int __init init_chess_player(void)
{
        struct work_struct *chesswork;
        /*init player and register it*/
        player.id=0x01;
        player.status=0; /*wait*/
        player.go=1; /*deffensize*/
        player.piece='1';
        registerplayer(&player);
/*
        player.x=0;
        player.y=0;

        runonestep(&player);
        */

        wq = create_singlethread_workqueue("my_chess_queue");
        chesswork = kmalloc(sizeof(struct work_struct), GFP_KERNEL);

        /*init the work struct*/
        INIT_WORK(chesswork,play);

        queue_work(wq, chesswork);


        return 0;
}

module_init(init_chess_player);

static void __exit exit_chess_player(void)
{
        flush_workqueue(wq);
        destroy_workqueue(wq);
        printk(KERN_INFO "exit_chess-->\n");
}

module_exit(exit_chess_player);
                                                

Because module dependency, the source file should be at same directory.

Makefile,

obj-m += chess.o
obj-m += chessplayer0.o
obj-m += chessplayer1.o
KDIR := /usr/src/linux-headers-2.6.32-41-generic
PWD := $(shell pwd)

all:
    $(MAKE) -C $(KDIR) M=$(PWD) modules


How to play?

$sudo insmod chess.ko                  //have to insmod it firstly, because chessplayer0.ko and chessplayer1.ko depend on it.

$sudo insmod chessplayer0.ko

$sudo insmod chessplayer1.ko

$tail -f /var/log/syslog                    // watch game







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值