linux-0.11系统添加信号量功能实验并验证

添加系统调用接口

在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中的信号量名字并没有写入内核区,待改善。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值