操作系统原理与实践-信号量的实现和应用

include/linux/sys.h 下增加 

extern int sys_sem_open();
extern int sys_sem_close();
extern int sys_sem_wait();
extern int sys_sem_post();
extern int sys_sem_count();

fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,
sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,
sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,
sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,
sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,
sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,
sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
sys_setreuid, sys_setregid, sys_sem_open, sys_sem_close, sys_sem_wait, sys_sem_post, sys_sem_count };

kernel/system_call.s

nr_system_calls = 77

kernel/Makefile

sem.s sem.o: sem.c ../include/linux/kernel.h ../include/unistd.h
exit.s exit.o: exit.c ../include/errno.h ../include/signal.h \
  ../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \
  ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
  ../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \
  ../include/asm/segment.h

kernel/sem.c

#include <asm/segment.h>
#include <asm/system.h>
#include <linux/sched.h>
struct sem {
    char name[64];
    int value;
    int len;
    char valid;
    struct task_struct *wait;
};

struct sem arr[64];

int sys_sem_open(const char *name, char* value, char *handle)
{
    //printk("size int : %d\n", sizeof(int));
    char buff[8];
    int len = *((int*)(value+4));
    int v = *((int*)(value));
    int i = 0;
    int flag;
    int j = 0;
    char _name[64];
    for (i = 0; i < 8; ++ i) {
        buff[i] = get_fs_byte(value+i);        
    }
    len = *((int*)(buff));
    v = *((int*)(buff+4));
    //printk("len = %d\n", len);
    //printk("v = %d\n", v);
    for (i = 0; i < 64; ++ i) {
        _name[i] = 0;
    }
    for (i = 0; i < len; ++ i) {
        _name[i] = get_fs_byte(name+i);        
    }
    //printk("sem_name = %s\n", _name);
    char h = -1;
    for (i = 0; i < 64; ++ i) {
        if (arr[i].valid == 1 && arr[i].len == len) {
           flag = 1;
           for (j = 0; j < len; ++ j) {
               if (arr[i].name[j] != _name[j]) {
                   flag = 0;
                   break;
               }
           }
           if (flag) {
               h = i;
           }
        } 
    }
    //printk("h0 = %d\n", h); 
    if (h == -1) {
        for (i = 0; i < 64; ++ i) {
            if (arr[i].valid == 0) {
                h = i;
                arr[i].valid = 1;
                arr[i].len = len;
                for (j = 0; j < 64; ++j) {
                     arr[i].name[j] = 0;
                }
//printk("name = %s\n", _name);
                for (j = 0; j < len; ++j) {
                     arr[i].name[j] = _name[j];
                }
//printk("arr name = %s\n", arr[i].name);
                arr[i].value = v;
                break;
            }
        }
    //printk("h1 = %d\n", h); 
    }
    if (h == -1) {
       return -1;
    } else {
       put_fs_byte(h, handle);
    }
    return 0;
}

int sys_sem_close(char *name, int len)
{
    char _name[64];
    int i, j, flag;
    for (i = 0; i < 64; ++ i) {
        _name[i] = 0;
    }
    for (i = 0; i < len; ++ i) {
        _name[i] = get_fs_byte(name+i);        
    }
    for (i = 0; i < 64; ++ i) {
        if (arr[i].valid && arr[i].len == len) {
            flag = 1;
            for (j = 0; j < len; ++ j) {
                if (arr[i].name[j] != _name[j]) {
                    flag = 0;
                    break;
                }
            }
            if (flag) {
                arr[i].valid = 0;
                printk("close succ %s %d\n", _name, i);
                return 0;
            }
        }

    } 
    return -1;
}

int sys_sem_wait(char ch)
{
    int i = ch;
    if (i >= 64) {
        return -1;
    }
    if (arr[i].valid == 0) {
        return -2;
    }
    //printk("%d: wait %s %d\n", current->pid, arr[i].name, arr[i].value);
     
    while (arr[i].value <= 0) {
        sleep_on(&(arr[i].wait));
        if (arr[i].valid == 0) {
           return -3;
        }
    }
    arr[i].value --;
    return 0;
}

int sys_sem_post(char ch)
{
    int i = ch;
    if (i >= 64) {
        return -1;
    }
    if (arr[i].valid == 0) {
        return -2;
    }
    //printk("%d: post %s\n", current->pid, arr[i].name);
    arr[i].value ++;
    wake_up(&(arr[i].wait));
    return 0;
}

int sys_sem_count()
{
    int i;
    int cnt = 0;
    for (i = 0; i < 64; ++ i) {
        if (arr[i].valid == 1) {
            cnt ++;
        }
    }
    printk("kernel sem count = %d\n", cnt);
    return 0;
}

用户态测试代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define __LIBRARY__
#include "unistd.h"
#define __NR_sem_open 72
#define __NR_sem_close 73
#define __NR_sem_wait 74
#define __NR_sem_post 75
#define __NR_sem_count 76

#include "string.h"

_syscall3(int, sem_open, const char*, name, char*, value, char*, addr);
_syscall2(int, sem_close, const char*, name, int, len);
_syscall1(int, sem_wait, char, ch);
_syscall1(int, sem_post, char, ch);
_syscall0(int, sem_count);
int _sem_open(const char* name, int len, int value, char* addr)
{
    char buff[8];
    memcpy(buff, (char*)&len, 4);
    memcpy(buff+4, (char*)&value, 4);
    return sem_open(name, buff, addr);
}

int fi, fo;
char mutex, empty, full, tty;
const char *name = "mutex";
const char *empty_name = "empty";
const char *full_name = "full";
const char *tty_name = "tty";

#define mmax 500 
#define cnum 10
void producer()
{
    int i = 0;
    for (i = 0; i < mmax; ++ i) {
        sem_wait(empty);
        sem_wait(mutex);
        write(fi, (char*)&i, 4);
        sem_post(mutex);
        sem_post(full);
    }
}

void close_sems()
{
    sem_close(name, strlen(name));
    sem_close(empty_name, strlen(empty_name));
    sem_close(full_name, strlen(full_name));
    sem_close(tty_name, strlen(tty_name)); 
}

void consumer()
{
    int i, j, ret;
    int pid = getpid();
    while(1) {
        ret = sem_wait(full);
        if (ret < 0) {
           printf("%d exiting.", pid);
           return;
        }
        sem_wait(mutex);
        read(fo, (char*)&i, 4);
        sem_post(mutex);
        sem_wait(tty);
        printf("pid = %d i = %d\n", pid, i);
        fflush(stdout);
        sem_post(tty);
        sem_post(empty);
        if (i == mmax-1) {
            close_sems();
        }
    }
}

int main()
{
    int i = 0;
    int ret = _sem_open(name, strlen(name), 1, &mutex);
    ret = _sem_open(empty_name, strlen(empty_name), 1, &empty);
    ret = _sem_open(full_name, strlen(full_name), 0, &full);
    ret = _sem_open(tty_name, strlen(tty_name), 1, &tty);
    fi = open("./ppp", O_WRONLY|O_CREAT|O_TRUNC, 0777);
    fo = open("./ppp", O_RDONLY, 0777);
    for (i = 0; i < cnum; ++ i) {
        if (fork() == 0) {
           consumer();
           return 0;
        }
    }
    producer();
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值