信号量的实现和应用

一.添加信号量系统调用

1.修改unistd.h,如系统调用实验,需要将unistd.h的改动写到bochs中

/* add */
#include <sys/sem.h>
/* end */
/* add */
#define __NR_sem_open 72
#define __NR_sem_wait 73
#define __NR_sem_post 74
#define __NR_sem_unlink 75
/* end */
/* add */
sem_t *sem_open(const char *name, unsigned int value);
int sem_wait(sem_t *sem);
int sem_post(sem_t *sem);
int sem_unlink(const char *name);
/* end */

2.新建sem.h

在include/sys/目录下新建sem.h

/* add by jlb */
#ifndef _SEM_H
#define _SEM_H

/* include task_struct */
#include <linux/sched.h>

#define NAME_SIZE 10
/* add */
typedef struct { char name[NAME_SIZE]; unsigned int value; struct task_struct *wait; char used; } sem_t;
/* end */

#endif

3.修改system_call.s

/* mod by jlb */
nr_system_calls = 76

4.修改sys.h

/* add */
extern int sys_sem_open();
extern int sys_sem_wait();
extern int sys_sem_post();
extern int sys_sem_unlink();
/* end */

fn_ptr sys_call_table[] = { sys_setup,  ......
sys_setregid, sys_sem_open, sys_sem_wait, sys_sem_post, sys_sem_unlink };

5.新增sem.c

kernel/目录下新建sem.c

/* add by jlb */
#include <sys/sem.h>
#include <errno.h>
/* include get_fs_byte() */
#include <asm/segment.h>
/* include NULL */
#include <unistd.h>
/* include cli() sti() */
#include <asm/system.h>
/* include prknik() */
#include <linux/kernel.h>

#define KSEM_SIZE 5

sem_t ksem[KSEM_SIZE] = {{{'0', }, 0, NULL, 0}, {{'\0', }, 0, NULL, 0}, {{'0', }, 0, NULL, 0}, {{'0', }, 0, NULL, 0}, {{'0', }, 0, NULL, 0}};

char buf[NAME_SIZE];

int str_equ(const char * sa,const char * sb)
{
   int i;
   for (i=0; sa[i] && sb[i]; i++)
       if (sa[i] != sb[i])
           return 0;
   return 1;

}

void str_cpy(char * dest,const char * src)
{
   int i;
   for (i=0; dest[i] = src[i]; i++) ;
}

sem_t * sys_sem_open(const char *name, unsigned int value)
{    
   int i;
   /* get name */
   for (i=0; buf[i] = get_fs_byte(name+i); i++) ;

   /* return old sem */
   for (i=0; i<KSEM_SIZE; i++)
       if (ksem[i].used) {
           if (str_equ(ksem[i].name, buf)) {
               /* debug */
               printk("old: buf: %s\n", buf);
               printk("old: %s, %d, %d, %d\n", ksem[i].name, ksem[i].value, ksem[i].wait, ksem[i].used);
               return &ksem[i];
           }
       }        

   /* create new sem */
   for (i=0; i<KSEM_SIZE; i++)
       if (!ksem[i].used) {
           str_cpy(ksem[i].name, buf);
           ksem[i].value = value;
           ksem[i].wait = NULL;
           ksem[i].used = 1;
           /* debug */
           printk("new: %s\n", buf);
           printk("new: %s, %d, %d, %d\n", ksem[i].name, ksem[i].value, ksem[i].wait, ksem[i].used);
           return &ksem[i];
       }    

   /* no sem */
   return NULL;
}

int sys_sem_wait(sem_t *sem)
{
   cli();    
   while (!sem->value) 
       sleep_on(&sem->wait);
   sem->value--;
   sti();
   return 0;
}

int sys_sem_post(sem_t *sem)
{
   cli();
   if (!sem->value)
       wake_up(&sem->wait);
   sem->value++;
   sti();
   return 0;
}

int sys_sem_unlink(const char *name)
{
   int i;
   /* get name */
   for (i=0; buf[i] = get_fs_byte(name+i); i++) ;

   /* try to delete sem */
   for (i=0; i<KSEM_SIZE; i++)
       if (ksem[i].used)
           if (str_equ(ksem[i].name, buf)) {
               ksem[i].used = 0;
               return 0;
           }    
   return -ERROR;
}

6.修改makefile

# mod by jlb
OBJS  = sched.o system_call.o traps.o asm.o fork.o \
    panic.o printk.o vsprintf.o sys.o exit.o \
    signal.o mktime.o sem.o
copy
# mod by jlb
sem.s sem.o : sem.c ../include/sys/sem.h ../include/errno.h ../include/asm/segment.h \
  ../include/unistd.h ../include/linux/sched.h ../include/asm/system.h ../include/linux/kernel.h

二 编写pc.c

#define __LIBRARY__
#include <unistd.h>
/* include some constant */
#include <fcntl.h>
/* include printf() fflush() */
#include <stdio.h>
#include <sys/sem.h>

_syscall0(int, fork)
_syscall0(int, getpid)
_syscall3(int, write, int, fildes, const char *, buf, off_t, count)
_syscall3(int, read, int, fildes, char *, buf, off_t, count)
_syscall3(int, lseek, int, fildes, off_t, offset, int, origin)
_syscall0(int, sync);

_syscall2(sem_t *, sem_open, const char *, name, unsigned int, value)
_syscall1(int, sem_wait, sem_t *, sem)
_syscall1(int, sem_post, sem_t *, sem)
_syscall1(int, sem_unlink, const char *, name)

#define BUF_SIZE 10

#define FILE_BUF_SIZE 10

int main(void)
{
    int pid;
    int fd_p, fd_c;
    /* count used by producer 1 */
    unsigned short count = 0;
    /* used by all consumers */
    unsigned short tmp = 0;
    unsigned char buf[BUF_SIZE] = {0};
    /* empty = 10, full = 0, mutex = 1. above 1 is unlocked, 0 is locked */
    char name_empty[10] = "empty";
    char name_full[10] = "full";
    char name_mutex[10] = "mutex";
    sem_t * empty, * full, * mutex;

    /* file, read and write */
    fd_p = open("./f", O_CREAT|O_TRUNC|O_RDWR, 0666);
    fd_c = open("./f", O_CREAT|O_TRUNC|O_RDWR, 0666);

    /* close old semaphore */
    sem_unlink(name_empty);
    sem_unlink(name_full);
    sem_unlink(name_mutex);

    /* open new semaphore */
    empty = sem_open(name_empty, FILE_BUF_SIZE);
    full = sem_open(name_full, 0);
    mutex = sem_open(name_mutex, 1);

    /* consumer 1 */
    if (!fork()) {
        pid = getpid();
        while (1) {
            sem_wait(full); 
            sem_wait(mutex);

            read(fd_c, buf, sizeof(unsigned short));    
            /* lower | higher */
            tmp = (unsigned short)buf[0] | ((unsigned short)buf[1] << 8);
            /* debug
            printf("%d, %d\n", (unsigned short)buf[0], (unsigned short)buf[1] << 8);
            */
            printf("Consumer 1 process %d : %d\n", pid, tmp);
            fflush(stdout);
            /* set file pos is 0 */
            if (tmp % FILE_BUF_SIZE == 9)
                lseek(fd_c, 0, SEEK_SET);

            sem_post(mutex);
            sem_post(empty);
        }
        return 0;
    }

    /* consumer 2 */
    if (!fork()) {
        pid = getpid();
        while (1) {
            sem_wait(full); 
            sem_wait(mutex);

            read(fd_c, buf, sizeof(unsigned short));    
            /* lower | higher */
            tmp = (unsigned short)buf[0] | ((unsigned short)buf[1] << 8);
            /* debug
            printf("%d, %d\n", (unsigned short)buf[0], (unsigned short)buf[1] << 8);
            */
            printf("Consumer 2 process %d : %d\n", pid, tmp);
            fflush(stdout);
            /* set file pos is 0 */
            if (tmp % FILE_BUF_SIZE == 9)
                lseek(fd_c, 0, SEEK_SET);

            sem_post(mutex);
            sem_post(empty);
        }
        return 0;
    }

    /* consumer 3 */
    if (!fork()) {
        pid = getpid();
        while (1) {
            sem_wait(full); 
            sem_wait(mutex);

            read(fd_c, buf, sizeof(unsigned short));    
            /* lower | higher */
            tmp = (unsigned short)buf[0] | ((unsigned short)buf[1] << 8);
            /* debug
            printf("%d, %d\n", (unsigned short)buf[0], (unsigned short)buf[1] << 8);
            */
            printf("Consumer 3 process %d : %d\n", pid, tmp);
            fflush(stdout);
            /* set file pos is 0 */
            if (tmp % FILE_BUF_SIZE == 9)
                lseek(fd_c, 0, SEEK_SET);

            sem_post(mutex);
            sem_post(empty);
        }
        return 0;
    }

    /* producer 1 */
    pid = getpid();
    while (count <= 500) {
        sem_wait(empty);
        sem_wait(mutex);

        /* get lower */
        buf[0] = (unsigned char)count;
        /* get higher */
        buf[1] = (unsigned char) (count >> 8);
        write(fd_p, buf, sizeof(unsigned short));
        sync();
        /* debug 
        printf("%d, %d\n", buf[0], buf[1]);
        printf("Producer 1 process %d : %d\n", pid, count);
        fflush(stdout);
        */
        /* set file pos is 0 */
        if (count % FILE_BUF_SIZE == 9)
            lseek(fd_p, 0, SEEK_SET);
        count++;

        sem_post(mutex);
        sem_post(full);
    }

    return 0;
}

运行

./run
gcc -o pc pc.c
./pc >1.log
more 1.log

转载自 https://www.lanqiao.cn/courses/reports/1321123/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值