添加系统调用接口
在kernel文件夹中的sem.c文件添加sem_open、sem_wait、sem_post、sem_unlink等接口:
int sys_sem_open(const char *name, unsigned int value);
int sys_sem_wait(sem_t *sem);
int sys_sem_post(sem_t *sem);
int sys_sem_unlink(const char *name);
1、编写sem.c文件
// linux-0.11/kernel/sem.c
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/system.h>
#include <string.h>
#define MAX_NAME_LEN (32)
#define MAX_SEM_NUM (64)
struct sem_s {
char name[MAX_NAME_LEN];
int max_value;
int value;
struct task_struct *b_wait;
int enable;
};
typedef struct sem_s sem_t;
struct sem_list_info {
sem_t *sem_list[MAX_SEM_NUM];
int index;
};
struct sem_list_info sem_info = {0};
static int find_sem(const char *name)
{
int i = 0;
for (i = 0; i < MAX_SEM_NUM; i++)
{
if (!sem_info.sem_list[i])
{
continue;
}
if (0 == strcmp(sem_info.sem_list[i]->name, name))
{
return i;
}
}
return -1;
}
int sys_sem_open(const char *name, unsigned int value)
{
sem_t *sem = 0;
int i = 0;
int index = find_sem(name);
cli();
if (-1 == index) // new sem, need create it
{
for (i = 0; i < MAX_SEM_NUM; i++)
{
if (!sem_info.sem_list[i])
{
sem_info.sem_list[i] = malloc(sizeof(sem_t));
sem_info.sem_list[i]->max_value = value;
sem_info.sem_list[i]->value = value;
sem_info.sem_list[i]->enable = 1;
sem = sem_info.sem_list[i];
break;
}
}
}
else
{
sem_info.sem_list[index]->enable = 1;
sem = sem_info.sem_list[index];
}
sti();
return sem;
}
int sys_sem_wait(sem_t *sem)
{
if (!sem || !sem->enable) {return -1;}
int i = 0;
cli();
if (--sem->value < 0) // if the value is less than 0, save the info and enter the schedule
{
sleep_on(&(sem->b_wait));
}
sti();
return i;
}
int sys_sem_post(sem_t *sem)
{
if (!sem || !sem->enable) {return -1;}
int i = 0;
cli();
sem->value++;
wake_up(&(sem->b_wait));
sti();
return i;
}
int sys_sem_unlink(const char *name)
{
int i = 0;
int index = find_sem(name);
cli();
if (index >= 0)
{
free(sem_info.sem_list[index]);
}
sti();
return i;
}
2、修改Makefile,添加sem相关依赖
// linux0.11/kernel/Makefile
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
sem.s sem.o: sem.c ../include/linux/sched.h ../include/linux/kernel.h \
../include/asm/system.h
3、修改系统调用表,在相应位置添加下列代码
// linux-0.11/include/linux/sys.h
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_sem_open,
sys_sem_wait, sys_sem_post , sys_sem_unlink };
4、修改系统调用接口数量
// linux-0.11/kernel/system_call.s
nr_system_calls = 76
5、修改运行系统中的unistd.h,添加下列代码
// linux-0.11/include/unistd.h
#define __NR_semopen 72
#define __NR_semwait 73
#define __NR_sempost 74
#define __NR_semunlink 75
struct sem_s {
char name[MAX_NAME_LEN];
int max_value;
int value;
struct task_struct *b_wait;
int enable;
};
typedef struct sem_s sem_t; // 添加这个是为了客户端代码编译使用
6、编译代码(make clean && make all),此时与内核相关的代码已添加完成
测试验证
1、编写客户端代码
// linux-0.11系统运行是的文件系统路径下/pc.c
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
int sem_open(const char* name,unsigned int value)
{
long __res;
__asm__ volatile ("int $0x80"
: "=a" (__res)
: "0" (72),"b" ((long)(name)),"c" ((long)(value)));
if (__res >= 0)
return (int) __res;
errno = -__res;
return -1;
}
int sem_wait(sem_t* sem)
{
long __res;
__asm__ volatile ("int $0x80"
: "=a" (__res)
: "0" (73),"b" ((long)(sem)));
if (__res >= 0)
return (int) __res;
errno = -__res;
return -1;
}
int sem_post(sem_t* sem)
{
long __res;
__asm__ volatile ("int $0x80"
: "=a" (__res)
: "0" (74),"b" ((long)(sem)));
if (__res >= 0)
return (int) __res;
errno = -__res;
return -1;
}
int sem_unlink(const char* name)
{
long __res;
__asm__ volatile ("int $0x80"
: "=a" (__res)
: "0" (75),"b" ((long)(name)));
if (__res >= 0)
return (int) __res;
errno = -__res;
return -1;
}
void write_buff(FILE *fl, int data, int pos)
{
fseek(fl, 4 * pos, SEEK_SET);
fwrite(&data, sizeof(int), 1, fl);
fflush(fl);
}
void read_buff(FILE *fl, int *data, int pos)
{
fseek(fl, 4 * pos, SEEK_SET);
fread(data, sizeof(int), 1, fl);
}
int main(int argc, char **argv)
{
#define BUFF_LEN (10)
#define MAX_SIZE (500)
#define WRITE_POS (0)
#define READ_POS (1)
#define COUNT_POS (2)
int i = 0;
int data;
int index;
int count;
sem_t *sem_empty = NULL;
sem_t *sem_full = NULL;
sem_t *sem_mutex = NULL;
FILE *fl = NULL;
FILE *result = NULL;
FILE *file_value = NULL;
pid_t producerId = -1;
pid_t consumer1Id = -1;
pid_t consumer2Id = -1;
pid_t consumer3Id = -1;
pid_t consumer4Id = -1;
sem_empty = (sem_t *)sem_open("EMPTY", BUFF_LEN);
sem_full = (sem_t *)sem_open("FULL", 0);
sem_mutex = (sem_t *)sem_open("MUTEX", 1);
fl = fopen("/var/buff.txt", "wb+");
if (fl == NULL)
{
printf("can not open buff by wb+ \n");
return 0;
}
result = fopen("/var/result.txt", "wb+");
if (result == NULL)
{
printf("can not open result buff by wb+ \n");
return 0;
}
file_value = fopen("/var/filevalue.txt", "wb+");
if (file_value == NULL)
{
printf("can not open result buff by wb+ \n");
return 0;
}
write_buff(file_value, 0, WRITE_POS);
write_buff(file_value, 0, READ_POS);
write_buff(file_value, 0, COUNT_POS);
if ((producerId = fork()) == 0)
{
for (i = 0; 1 <= MAX_SIZE; i++)
{
sem_wait(sem_empty);
sem_wait(sem_mutex);
read_buff(file_value, &index, WRITE_POS);
write_buff(fl, i, index);
fprintf(result, "write: %d\n", i);
fflush(result);
index = (index + 1) % BUFF_LEN;
write_buff(file_value, index, WRITE_POS);
sem_post(sem_mutex);
sem_post(sem_full);
}
exit(0);
}
else if ((consumer1Id = fork()) == 0)
{
for (;;)
{
sem_wait(sem_full);
sem_wait(sem_mutex);
read_buff(file_value, &index, READ_POS);
read_buff(fl, &data, index);
fprintf(result, "pid1:%d: read data = %d, read index = %d\n", getpid(), data, index);
fflush(result);
index = (index + 1) % BUFF_LEN;
write_buff(file_value, index, READ_POS);
read_buff(file_value, &count, COUNT_POS);
count++;
write_buff(file_value, count, COUNT_POS);
if (count >= MAX_SIZE)
{
break;
}
sem_post(sem_mutex);
sem_post(sem_empty);
}
exit(0);
}
else if ((consumer2Id = fork()) == 0)
{
for (;;)
{
sem_wait(sem_full);
sem_wait(sem_mutex);
read_buff(file_value, &index, READ_POS);
read_buff(fl, &data, index);
fprintf(result, "pid2:%d: read data = %d, read index = %d\n", getpid(), data, index);
fflush(result);
index = (index + 1) % BUFF_LEN;
write_buff(file_value, index, READ_POS);
read_buff(file_value, &count, COUNT_POS);
count++;
write_buff(file_value, count, COUNT_POS);
if (count >= MAX_SIZE)
{
break;
}
sem_post(sem_mutex);
sem_post(sem_empty);
}
exit(0);
}
else if ((consumer3Id = fork()) == 0)
{
for (;;)
{
sem_wait(sem_full);
sem_wait(sem_mutex);
read_buff(file_value, &index, READ_POS);
read_buff(fl, &data, index);
fprintf(result, "pid3:%d: read data = %d, read index = %d\n", getpid(), data, index);
fflush(result);
index = (index + 1) % BUFF_LEN;
write_buff(file_value, index, READ_POS);
read_buff(file_value, &count, COUNT_POS);
count++;
write_buff(file_value, count, COUNT_POS);
if (count >= MAX_SIZE)
{
break;
}
sem_post(sem_mutex);
sem_post(sem_empty);
}
exit(0);
}
else if ((consumer4Id = fork()) == 0)
{
for (;;)
{
sem_wait(sem_full);
sem_wait(sem_mutex);
read_buff(file_value, &index, READ_POS);
read_buff(fl, &data, index);
fprintf(result, "pid4:%d: read data = %d, read index = %d\n", getpid(), data, index);
fflush(result);
index = (index + 1) % BUFF_LEN;
write_buff(file_value, index, READ_POS);
read_buff(file_value, &count, COUNT_POS);
count++;
write_buff(file_value, count, COUNT_POS);
if (count >= MAX_SIZE)
{
break;
}
sem_post(sem_mutex);
sem_post(sem_empty);
}
exit(0);
}
wait(NULL);
sem_unlink("EMPTY");
sem_unlink("FULL");
sem_unlink("MUTEX");
fclose(fl);
fclose(result);
fclose(file_value);
return 0;
}
2、在修改的运行的系统中编译客户端程序,并运行
3、观察程序输出结果
4、其中result.txt是我们测试的结果保存文件
- 从这里可以看出4个读进程在有序读取一个生产进程的写数据。
5、测试程序去掉信号量代码保护后再次运行观察结果
- 发现生产者进程与消费者进程不在序列里写数据-读数据
总结
此实验主要测试了linux-0.11系统中添加信号量功能后使用多进程之间协同工作的效果,符合预期要求。但是不足的是在sem.c中的信号量名字并没有写入内核区,待改善。