天天看點

作業系統之位址映射與共享實驗

實驗内容

1、用Bochs調試工具跟蹤Linux 0.11的位址翻譯(位址映射)過程,了解IA-32和Linux 0.11的記憶體理機制。

2、在Ubuntu上編寫多程序的生産者—消費者程式,用共享記憶體做緩沖。

3、在信号量實驗的基礎上,為Linux 0.11增加共享記憶體功能,并将生産者—消費者程式移植到Linux 0.11。

跟蹤位址翻譯過程

1、編寫view-memory.c檔案:

#include <stdio.h>
int i = 0x12345678;
int main(void)
{
	printf("The logic or virtual address of i is 0x%08x\n", &i);
	while(i);
	return 0;
}
           

2、使用bochs跟蹤位址翻譯

作業系統之位址映射與共享實驗

寫的很亂。。。。。下回有時間再完善

編寫shmget和shmat系統調用

// linux-0.11/mm/shm.c
#include <linux/mm.h>
#include <linux/sched.h>
#include <errno.h>

#define COUNT (10)
#define SIZE_MAX  (4096)
unsigned long share_physical_address[COUNT] = {0};

/* create or open a page of the share memroy */
int sys_shmget(int key, size_t size, int shmflg)
{
	// forbid it that more than 4K size
	if (key < 0 || key >= COUNT || size > SIZE_MAX)
	{
		errno = EINVAL; 
		return -1;
	}

	// allocate a page of the free page from the physical memroy
	if (0 == share_physical_address[key])
	{
		share_physical_address[key] = get_free_page();
		if (0 == share_physical_address[key])
		{
			errno = EINVAL; 
			return -1;
		}
	}
	printk("sys_shmget: address = %d\n", share_physical_address[key]);
	return share_physical_address[key];
}

/* get logic address of the memory address */
int sys_shmat(int shmid, const void *shmaddr, int shmflg)
{
	unsigned long data_base = 0; 
	unsigned long data_limit = 0; 
	if (shmid == -1)
	{
		errno = EINVAL;
		return 0;
	}
	
	// establish a mapping between the physical page and the current virtual breakpoint 
	put_page(shmid, (current->start_code + current->brk));
	
	printk("sys_shmat: current->brk = %d\n", current->brk);

	return current->brk;
}
           

然後再更改一些編譯這系統調用的依賴,通過修改Makefile、system_call.s等檔案。

添加sem.c信号量系統調用檔案

// linux-0.11/kernel/sem.c
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <string.h>
#include <stdarg.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 void get_fs_buff(const char *name, char*buff, int size)
{
	int i;
	memset(buff, 0, size);
	for (i = 0; i < size; i++)
	{
		buff[i] = get_fs_byte(name++);
		if (buff[i] == '\0')
		{
			break;
		}
	}
}

static int find_sem(const char *name, char *buf)
{
	int i = 0;
	get_fs_buff(name, buf, 1024);
	for (i = 0; i < MAX_SEM_NUM; i++)
	{
		if (!sem_info.sem_list[i])
		{
			continue;
		}
		printk("find_sem: sem_info.sem_list[i]->name = %s\n", sem_info.sem_list[i]->name);
		if (0 == strcmp(sem_info.sem_list[i]->name, buf))
		{
			printk("find_sem: buf = %s\n", buf);
			return i;
		}
	}
	return -1;
}



int sys_sem_open(const char *name, unsigned int value)
{
	sem_t *sem = 0;
	int i = 0;
	char buf[1024] = {0};
	int index = find_sem(name, buf);
	printk("sys_sem_open: %s\n", buf);
	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;
				strcpy(sem_info.sem_list[i]->name, buf);
				printk("sys_sem_open: %s, i = %d\n", buf, i);
				sem = sem_info.sem_list[i];
				index = i;
				break;
			}
		}
	}
	else
	{
		sem_info.sem_list[index]->enable = 1;
		sem = sem_info.sem_list[index];
	}
	sti();
	printk("sys_sem_open: %s, index = %d\n", sem_info.sem_list[i]->name, index);
	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;
	char buf[1024] = {0};
	int index = find_sem(name, buf);
	cli();
	if (index >= 0 && sem_info.sem_list[index])
	{
		free(sem_info.sem_list[index]);
		printk("sys_sem_unlink: %s\n", buf);
	}
	sti();
	return i;
}
           

怎麼說呢,這個sem.c可以驗證本實驗,但是由于時序上沒有做嚴格處理,是以需要待完善的。這裡我用一些printk來延時處理時序上的沖突。

編寫producer.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; 
}

int shmget(int key, size_t size,int shmflg) 
{ 
	long __res; 
	__asm__ volatile ("int $0x80" 
		: "=a" (__res) 
		: "0" (76),"b" ((long)(key)),"c" ((long)(size)),"d" ((long)(shmflg))); 
	if (__res>=0) 
		return (int) __res; 
	errno=-__res; 
	return -1; 
}

int shmat(int shmid, const void * shmaddr, int shmflg) 
{ 
	long __res; 
	__asm__ volatile ("int $0x80" 
		: "=a" (__res) 
		: "0" (77),"b" ((long)(shmid)),"c" ((long)(shmaddr)),"d" ((long)(shmflg))); 
	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);
}

char *buff = 0;
int *value_index = 0;
int main(int argc, char **argv)
{
#define BUFF_LEN (10)
#define MAX_SIZE (120)

	int shmid = 0;
	int share_memory_address = 0;
	sem_t *sem_empty = NULL;
	sem_t *sem_full = NULL;
	sem_t *sem_mutex = NULL;
	int i = 0;
	FILE *result = NULL;
	char *end_flag = 0;

	result = fopen("/var/restt", "wb+");
	if (result == NULL)
	{
		printf("can not open result buff by wb+ \n");
		return 0;
	}
	
	shmid = shmget(0, 0, 0);
	if (shmid == -1)
	{
		printf("can not allocate the share memory \n");
		return 0;
	}
	
	share_memory_address = shmat(shmid, 0, 0);
	if (share_memory_address == 0)
	{
		printf("can not allocate the virtual memory \n");
		return 0;
	}

	buff = (char*)share_memory_address;
	
	end_flag = (char*)(share_memory_address + 12);
	value_index = (int*)(share_memory_address + 16);

	*(int*)(share_memory_address + 22) = 1234;

	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);
	for (i = 0; i <= MAX_SIZE; i++)
	{
		sem_wait(sem_empty);  
		sem_wait(sem_mutex); 
		
		buff[*value_index] = i;
		fseek(result, 2, SEEK_END);
		fprintf(result, "write: %d, write_index:%d\n", buff[*value_index], *value_index);
		fflush(result);
		*value_index = (*value_index + 1) % BUFF_LEN;

		sem_post(sem_mutex);
		sem_post(sem_full);
	}
	
	while(*end_flag != 123);  // wait for the consumer  being finshed
	fclose(result);
	sem_unlink("EMPTY");
	sem_unlink("FULL");
	sem_unlink("MUTEX");

	printf("producer end\n");
	fflush(stdout);
	return 0;
}

           

編寫consumer.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; 
}

int shmget(int key, size_t size,int shmflg) 
{ 
	long __res; 
	__asm__ volatile ("int $0x80" 
		: "=a" (__res) 
		: "0" (76),"b" ((long)(key)),"c" ((long)(size)),"d" ((long)(shmflg))); 
	if (__res>=0) 
		return (int) __res; 
	errno=-__res; 
	return -1; 
}

int shmat(int shmid, const void * shmaddr, int shmflg) 
{ 
	long __res; 
	__asm__ volatile ("int $0x80" 
		: "=a" (__res) 
		: "0" (77),"b" ((long)(shmid)),"c" ((long)(shmaddr)),"d" ((long)(shmflg))); 
	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);
}

char *buff = 0;
int main(int argc, char **argv)
{
#define BUFF_LEN (10)
#define MAX_SIZE (120)

	int shmid = 0;
	int share_memory_address = 0;
	sem_t *sem_empty = NULL;
	sem_t *sem_full = NULL;
	sem_t *sem_mutex = NULL;
	int i = 0;
	int index = 0;
	int count = 0;
	FILE *result = NULL;
	int *end_flag = 0;
	int data = 0;

	result = fopen("/var/restt", "a");
	if (result == NULL)
	{
		printf("can not open result buff by wb+ \n");
		return 0;
	}
	
	shmid = shmget(0, 0, 0);
	if (shmid == -1)
	{
		printf("can not allocate the share memory \n");
		return 0;
	}
	
	share_memory_address = shmat(shmid, 0, 0);
	if (share_memory_address == 0)
	{
		printf("can not allocate the virtual memory \n");
		return 0;
	}

	buff = (char*)share_memory_address;

	end_flag = (char*)(share_memory_address + 12);
	
	data = *(int*)(share_memory_address + 22);
	printf("data: %d \n", data);

	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);
	for (;;)
	{
		sem_wait(sem_full);
		sem_wait(sem_mutex);
		fseek(result, 2, SEEK_END);
		fprintf(result, "pid:%d:  read data = %d, read index = %d\n", getpid(), buff[index], index);
		fflush(result);
		
		index = (index + 1) % BUFF_LEN;

		count++;
		if (count >= MAX_SIZE + 1)
		{
			*end_flag = 123;
			printf("consumer:end_flag = %d\n", *(char*)(share_memory_address + 12));
			break;
		}

		sem_post(sem_mutex);
		sem_post(sem_empty);
	}

	printf("consumer end\n");
	return 0;
}
           

編譯程式,運作程式

作業系統之位址映射與共享實驗
作業系統之位址映射與共享實驗

程式結束時,這個釋放空間的時候出現了問題,我猜是共享記憶體釋放的時候造成的,不過不影響我驗證這個位址映射與共享實驗,日後再完善把。

實驗結果

作業系統之位址映射與共享實驗
作業系統之位址映射與共享實驗

總結

從上面結果看,位址的共享确實成功了。本實驗中有很多待改善的地方,等有時間再完善。

繼續閱讀