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;
}