本文以记录实验过程为主,具体实验内容参考:实验指导书。
1 添加系统调用
1、首先在 unistd.h 文件中添加4个系统调用号:
...
#define __NR_setregid 71
#define __NR_sem_open 72
#define __NR_sem_wait 73
#define __NR_sem_post 74
#define __NR_sem_unlink 75
#define _syscall0(type,name) \
...
2、然后再添加信号量相关定义和声明(也在 unistd.h 文件中)
...
#endif
#define SEM_NAME_LEN 20
#define SEM_MAX 20
typedef struct sem_t{
char name[SEM_NAME_LEN];
int value;
struct task_struct *wait;
struct sem_t *next;
}sem_t;
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);
extern int errno;
...
3、在 kernel\system_call.s 中将系统调用总数修改为 76
nr_system_calls = 76
4、在 include\linux\sys.h 中添加系统调用声明,并将函数指针添加到 sys_call_table 中
extern int sys_sem_open();
extern int sys_sem_wait();
extern int sys_sem_post();
extern int sys_sem_unlink();
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, ... sys_sigaction, sys_sgetmask, sys_ssetmask,
sys_setreuid,sys_setregid, sys_sem_open, sys_sem_wait, sys_sem_post, sys_sem_unlink };
2 新增sem.c
在 kernel 目录下新建 sem.c 文件,然后修改 kernel 目录下的 makefile ,在 OBJS 中新增 sched.o,然后在 ### Dependencies: 下 添加 sem.s sem.o 的生成规则:
...
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
...
### Dependencies:
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 \
...
3 sem.c
sem.c 文件内容如下:
#include <unistd.h>
#include <asm/segment.h>
#include <string.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/system.h>
sem_t *sem_head = &((sem_t *){ "\0", 0, NULL, NULL });
sem_t* sys_sem_open(const char *name, unsigned int value)
{
sem_t *sem_current = NULL;
sem_t *sem_front = NULL;
char sem_name[SEM_NAME_LEN] = {'\0'};
int i = 0;
printk("sem_open:enter:");
while( (sem_name[i] = get_fs_byte(name + i)) != '\0')
{
if( (++i) >= SEM_NAME_LEN - 1){sem_name[i] = '\0'; break;}
}
for(sem_front = sem_head, sem_current = sem_head->next; sem_current != NULL; sem_front = sem_current, sem_current = sem_current->next)
{
if(0 == strcmp(sem_current->name, sem_name) )
{
printk("the semaphore is exist!\n");
return(sem_current);
}
}
if(NULL == sem_current)
{
sem_current = (sem_t *)malloc(sizeof(sem_t));
strcpy(sem_current->name, sem_name);
sem_current->value = value;
sem_current->next = NULL;
sem_front->next = sem_current;
}
printk("sem_open:exit\n");
return(sem_current);
}
int sys_sem_wait(sem_t *sem)
{
cli();
while(sem->value <= 0)
sleep_on( &(sem->wait) );
sem->value--;
sti();
return 0;
}
int sys_sem_post(sem_t *sem)
{
sem->value++;
if(sem->wait)
{
wake_up( &(sem->wait) );
return 0;
}
return -1;
}
int sys_sem_unlink(const char *name)
{
sem_t *sem_current = NULL;
sem_t *sem_front = sem_head;
char sem_name[SEM_NAME_LEN] = {'\0'};
int i = 0;
printk("sem_unlink:enter:");
while( (sem_name[i] = get_fs_byte(name + i)) != '\0')
{
if( (++i) >= SEM_NAME_LEN - 1){sem_name[i] = '\0'; break;}
}
for(sem_front = sem_head, sem_current = sem_head->next; sem_current && strcmp(sem_current->name, sem_name); sem_front = sem_current, sem_current = sem_current->next);
if(sem_current == NULL)
return -1;
sem_front->next = sem_current->next;
free(sem_current);
printk("unlink a sem\n");
return 0;
}
附录
附录1: Ubuntu下运行的 pc.c:
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <sys/types.h>
#include <stdio.h>
#include <signal.h>
#define BUFF_SIZE 10
#define FILENAME "./fileBuff.txt"
#define PRODUCT_NUM 500
#define CONSUMER_NUM 5
sem_t *Full, *Empty, *Mutex;
void consumer()
{
int fd = -1;
int buff[BUFF_SIZE];
int num = 0;
while(1)
{
sem_wait(Full);
sem_wait(Mutex);
fd = open(FILENAME, O_RDONLY);
num = read(fd, buff, BUFF_SIZE * sizeof(int)) / sizeof(int);
close(fd);
if(num > 0)
{
printf("%d : %d\n", getpid(), buff[0]);
fflush(stdout);
}
fd = open(FILENAME, O_WRONLY | O_TRUNC);
if(num > 1)
{
write(fd, &buff[1], (num - 1) * sizeof(int));
}
close(fd);
sem_post(Mutex);
sem_post(Empty);
}
}
void producter()
{
int fd = -1;
int i = 0;
for(i = 0; i < PRODUCT_NUM; i++)
{
sem_wait(Empty);
sem_wait(Mutex);
fd = open(FILENAME, O_WRONLY | O_APPEND);
write(fd, &i, sizeof(int));
close(fd);
sem_post(Mutex);
sem_post(Full);
}
}
int main()
{
int i = 0;
int fd = -1;
sem_unlink("Full");
sem_unlink("Empty");
sem_unlink("Mutex");
Full = sem_open("Full", O_CREAT, 0664, 0);
Empty = sem_open("Empty", O_CREAT, 0664, BUFF_SIZE);
Mutex = sem_open("Mutex", O_CREAT, 0664, 1);
fd = open(FILENAME, O_RDWR | O_CREAT | O_TRUNC, 0666);
close(fd);
for(i = 0; i < CONSUMER_NUM; i++)
{
if(!fork()) break;
}
if(5 != i)
{
consumer();
}
else
{
producter();
sleep(10);
}
sem_unlink("Full");
sem_unlink("Empty");
sem_unlink("Mutex");
kill(0, SIGKILL);
return 1;
}
附录2:Linux0.11下运行的 pc.c:
#define __LIBRARY__
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/stat.h>
_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 BUFF_SIZE 10
#define FILENAME "./fileBuff.txt"
#define DISPLAY "/usr/root/disFile.txt"
#define PRODUCT_NUM 100
#define CONSUMER_NUM 5
sem_t *Full, *Empty, *Mutex;
int displayFd;
void consumer()
{
int fd;
char buff[BUFF_SIZE] = {'\0'};
int count;
char pid;
int i = 0;
while(1)
{
sem_wait(Full);
sem_wait(Mutex);
fd = open(FILENAME, O_RDONLY);
count = read(fd, buff, BUFF_SIZE * sizeof(char)) / sizeof(char);
close(fd);
if(count > 0)
{
pid = getpid();
write(displayFd, &pid, 1);
write(displayFd, ":", 1);
write(displayFd, &buff[0], 1);
write(displayFd, "\n", 1);
}
fd = open(FILENAME, O_WRONLY | O_TRUNC);
if(count > 1)
{
write(fd, &buff[1], (count - 1) * sizeof(char));
}
close(fd);
sem_post(Mutex);
sem_post(Empty);
}
}
void producter()
{
int fd = -1;
char i = 0;
for(i = 0; i < PRODUCT_NUM; i++)
{
sem_wait(Empty);
sem_wait(Mutex);
fd = open(FILENAME, O_WRONLY | O_APPEND);
write(fd, &i, sizeof(char));
close(fd);
sem_post(Mutex);
sem_post(Full);
}
}
void main()
{
int i = 0;
int fd = -1;
Full = sem_open("Full", 0);
Empty = sem_open("Empty", BUFF_SIZE);
Mutex = sem_open("Mutex", 1);
displayFd = open(DISPLAY, O_RDWR | O_CREAT | O_TRUNC, 0666);
fd = open(FILENAME, O_RDWR | O_CREAT | O_TRUNC, 0666);
close(fd);
for(i = 0; i < CONSUMER_NUM; i++)
{
if(!fork()) break;
}
if(5 != i)
{
consumer();
}
else
{
producter();
sleep(10);
}
sem_unlink("Full");
sem_unlink("Empty");
sem_unlink("Mutex");
close(displayFd);
kill(0, SIGKILL);
}
|