这次试验,涉及前几次实验的综合运用,比较难,明天问老师之后,会逐步完善。
//======================================实验报告=========================================================
(1) 会出现不按顺序输出,或称是程序崩溃的情况。
有可能缓冲区满了,生产者还在写入数据,会造覆盖掉以前的数据,导致不按顺序输出。
或者缓冲区空了,消费者还在读数据,也会导致不按顺序输出。
因为没有 mutex 可能会出现多个线程并发访问临界区代码,造成崩溃。
(2)
不行,会出现死锁。当mutex信号为一,empty信号为0时,会出现死锁状态。
//=======================================================================================================
首先建立4个系统调用。sem_open sem_wait sem_post() sem_unlink()
需要修改
include/unistd.h
linux-0.11/kernel/system_call.s
linux-0.11/include/linux/sys.h
linux-0.11/kernel/makefile
这四个文件
自己编写
linux-0.11/kernel/sem.c (还不太会写)
pc.c (测试用,最好先在本地测试好,再放到0.11上去测)
两个文件
include/unistd.h是POSIX标准定义的unix类系统定义符号常量的头文件,在写系统调用时需要自己新建的数据类型啊,结构体啊,最好在此处声明
使用时include即可。(不要忘记unistd.h是要加在虚拟机中的)
#ifndef _UNISTD_H
#define _UNISTD_H
/* ok, this may be a joke, but I'm working on it */
#define _POSIX_VERSION 198808L
#define _POSIX_CHOWN_RESTRICTED /* only root can do a chown (I think..) */
#define _POSIX_NO_TRUNC /* no pathname truncation (but see in kernel) */
#define _POSIX_VDISABLE '\0' /* character to disable things like ^C */
/*#define _POSIX_SAVED_IDS */ /* we'll get to this yet */
/*#define _POSIX_JOB_CONTROL */ /* we aren't there quite yet. Soon hopefully */
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#ifndef NULL
#define NULL ((void *)0)
#endif
/* access */
#define F_OK 0
#define X_OK 1
#define W_OK 2
#define R_OK 4
/* lseek */
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
/* _SC stands for System Configuration. We don't use them much */
#define _SC_ARG_MAX 1
#define _SC_CHILD_MAX 2
#define _SC_CLOCKS_PER_SEC 3
#define _SC_NGROUPS_MAX 4
#define _SC_OPEN_MAX 5
#define _SC_JOB_CONTROL 6
#define _SC_SAVED_IDS 7
#define _SC_VERSION 8
/* more (possibly) configurable things - now pathnames */
#define _PC_LINK_MAX 1
#define _PC_MAX_CANON 2
#define _PC_MAX_INPUT 3
#define _PC_NAME_MAX 4
#define _PC_PATH_MAX 5
#define _PC_PIPE_BUF 6
#define _PC_NO_TRUNC 7
#define _PC_VDISABLE 8
#define _PC_CHOWN_RESTRICTED 9
#include
#include
#include
#include
#ifdef __LIBRARY__
#define __NR_setup 0 /* used only by init, to get system going */
#define __NR_exit 1
#define __NR_fork 2
#define __NR_read 3
#define __NR_write 4
#define __NR_open 5
#define __NR_close 6
#define __NR_waitpid 7
#define __NR_creat 8
#define __NR_link 9
#define __NR_unlink 10
#define __NR_execve 11
#define __NR_chdir 12
#define __NR_time 13
#define __NR_mknod 14
#define __NR_chmod 15
#define __NR_chown 16
#define __NR_break 17
#define __NR_stat 18
#define __NR_lseek 19
#define __NR_getpid 20
#define __NR_mount 21
#define __NR_umount 22
#define __NR_setuid 23
#define __NR_getuid 24
#define __NR_stime 25
#define __NR_ptrace 26
#define __NR_alarm 27
#define __NR_fstat 28
#define __NR_pause 29
#define __NR_utime 30
#define __NR_stty 31
#define __NR_gtty 32
#define __NR_access 33
#define __NR_nice 34
#define __NR_ftime 35
#define __NR_sync 36
#define __NR_kill 37
#define __NR_rename 38
#define __NR_mkdir 39
#define __NR_rmdir 40
#define __NR_dup 41
#define __NR_pipe 42
#define __NR_times 43
#define __NR_prof 44
#define __NR_brk 45
#define __NR_setgid 46
#define __NR_getgid 47
#define __NR_signal 48
#define __NR_geteuid 49
#define __NR_getegid 50
#define __NR_acct 51
#define __NR_phys 52
#define __NR_lock 53
#define __NR_ioctl 54
#define __NR_fcntl 55
#define __NR_mpx 56
#define __NR_setpgid 57
#define __NR_ulimit 58
#define __NR_uname 59
#define __NR_umask 60
#define __NR_chroot 61
#define __NR_ustat 62
#define __NR_dup2 63
#define __NR_getppid 64
#define __NR_getpgrp 65
#define __NR_setsid 66
#define __NR_sigaction 67
#define __NR_sgetmask 68
#define __NR_ssetmask 69
#define __NR_setreuid 70
#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) \
type name(void) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name)); \
if (__res >= 0) \
return (type) __res; \
errno = -__res; \
return -1; \
}
#define _syscall1(type,name,atype,a) \
type name(atype a) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(a))); \
if (__res >= 0) \
return (type) __res; \
errno = -__res; \
return -1; \
}
#define _syscall2(type,name,atype,a,btype,b) \
type name(atype a,btype b) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b))); \
if (__res >= 0) \
return (type) __res; \
errno = -__res; \
return -1; \
}
#define _syscall3(type,name,atype,a,btype,b,ctype,c) \
type name(atype a,btype b,ctype c) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); \
if (__res>=0) \
return (type) __res; \
errno=-__res; \
return -1; \
}
#endif /* __LIBRARY__ */
extern int errno;
int access(const char * filename, mode_t mode);
int acct(const char * filename);
int alarm(int sec);
int brk(void * end_data_segment);
void * sbrk(ptrdiff_t increment);
int chdir(const char * filename);
int chmod(const char * filename, mode_t mode);
int chown(const char * filename, uid_t owner, gid_t group);
int chroot(const char * filename);
int close(int fildes);
int creat(const char * filename, mode_t mode);
int dup(int fildes);
int execve(const char * filename, char ** argv, char ** envp);
int execv(const char * pathname, char ** argv);
int execvp(const char * file, char ** argv);
int execl(const char * pathname, char * arg0, ...);
int execlp(const char * file, char * arg0, ...);
int execle(const char * pathname, char * arg0, ...);
volatile void exit(int status);
volatile void _exit(int status);
int fcntl(int fildes, int cmd, ...);
int fork(void);
int getpid(void);
int getuid(void);
int geteuid(void);
int getgid(void);
int getegid(void);
int ioctl(int fildes, int cmd, ...);
int kill(pid_t pid, int signal);
int link(const char * filename1, const char * filename2);
int lseek(int fildes, off_t offset, int origin);
int mknod(const char * filename, mode_t mode, dev_t dev);
int mount(const char * specialfile, const char * dir, int rwflag);
int nice(int val);
int open(const char * filename, int flag, ...);
int pause(void);
int pipe(int * fildes);
int read(int fildes, char * buf, off_t count);
int setpgrp(void);
int setpgid(pid_t pid,pid_t pgid);
int setuid(uid_t uid);
int setgid(gid_t gid);
void (*signal(int sig, void (*fn)(int)))(int);
int stat(const char * filename, struct stat * stat_buf);
int fstat(int fildes, struct stat * stat_buf);
int stime(time_t * tptr);
int sync(void);
time_t time(time_t * tloc);
time_t times(struct tms * tbuf);
int ulimit(int cmd, long limit);
mode_t umask(mode_t mask);
int umount(const char * specialfile);
int uname(struct utsname * name);
int unlink(const char * filename);
int ustat(dev_t dev, struct ustat * ubuf);
int utime(const char * filename, struct utimbuf * times);
pid_t waitpid(pid_t pid,int * wait_stat,int options);
pid_t wait(int * wait_stat);
int write(int fildes, const char * buf, off_t count);
int dup2(int oldfd, int newfd);
int getppid(void);
pid_t getpgrp(void);
pid_t setsid(void);
#endif
linux-0.11/kernel/system_call.s 的修改与实验2大同小异
/*
* linux/kernel/system_call.s
*
* (C) 1991 Linus Torvalds
*/
/*
* system_call.s contains the system-call low-level handling routines.
* This also contains the timer-interrupt handler, as some of the code is
* the same. The hd- and flopppy-interrupts are also here.
*
* NOTE: This code handles signal-recognition, which happens every time
* after a timer-interrupt and after each system call. Ordinary interrupts
* don't handle signal-recognition, as that would clutter them up totally
* unnecessarily.
*
* Stack layout in 'ret_from_system_call':
*
* 0(%esp) - %eax
* 4(%esp) - %ebx
* 8(%esp) - %ecx
* C(%esp) - %edx
* 10(%esp) - %fs
* 14(%esp) - %es
* 18(%esp) - %ds
* 1C(%esp) - %eip
* 20(%esp) - %cs
* 24(%esp) - %eflags
* 28(%esp) - %oldesp
* 2C(%esp) - %oldss
*/
SIG_CHLD = 17
EAX = 0x00
EBX = 0x04
ECX = 0x08
EDX = 0x0C
FS = 0x10
ES = 0x14
DS = 0x18
EIP = 0x1C
CS = 0x20
EFLAGS = 0x24
OLDESP = 0x28
OLDSS = 0x2C
state = 0 # these are offsets into the task-struct.
counter = 4
priority = 8
signal = 12
sigaction = 16 # MUST be 16 (=len of sigaction)
blocked = (33*16)
# offsets within sigaction
sa_handler = 0
sa_mask = 4
sa_flags = 8
sa_restorer = 12
nr_system_calls = 76
/*
* Ok, I get parallel printer interrupts while using the floppy for some
* strange reason. Urgel. Now I just ignore them.
*/
.globl system_call,sys_fork,timer_interrupt,sys_execve
.globl hd_interrupt,floppy_interrupt,parallel_interrupt
.globl device_not_available, coprocessor_error
.align 2
bad_sys_call:
movl $-1,%eax
iret
.align 2
reschedule:
pushl $ret_from_sys_call
jmp schedule
.align 2
system_call:
cmpl $nr_system_calls-1,%eax
ja bad_sys_call
push %ds
push %es
push %fs
pushl %edx
pushl %ecx # push %ebx,%ecx,%edx as parameters
pushl %ebx # to the system call
movl $0x10,%edx # set up ds,es to kernel space
mov %dx,%ds
mov %dx,%es
movl $0x17,%edx # fs points to local data space
mov %dx,%fs
call sys_call_table(,%eax,4)
pushl %eax
movl current,%eax
cmpl $0,state(%eax) # state
jne reschedule
cmpl $0,counter(%eax) # counter
je reschedule
ret_from_sys_call:
movl current,%eax # task[0] cannot have signals
cmpl task,%eax
je 3f
cmpw $0x0f,CS(%esp) # was old code segment supervisor ?
jne 3f
cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?
jne 3f
movl signal(%eax),%ebx
movl blocked(%eax),%ecx
notl %ecx
andl %ebx,%ecx
bsfl %ecx,%ecx
je 3f
btrl %ecx,%ebx
movl %ebx,signal(%eax)
incl %ecx
pushl %ecx
call do_signal
popl %eax
3: popl %eax
popl %ebx
popl %ecx
popl %edx
pop %fs
pop %es
pop %ds
iret
.align 2
coprocessor_error:
push %ds
push %es
push %fs
pushl %edx
pushl %ecx
pushl %ebx
pushl %eax
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
movl $0x17,%eax
mov %ax,%fs
pushl $ret_from_sys_call
jmp math_error
.align 2
device_not_available:
push %ds
push %es
push %fs
pushl %edx
pushl %ecx
pushl %ebx
pushl %eax
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
movl $0x17,%eax
mov %ax,%fs
pushl $ret_from_sys_call
clts # clear TS so that we can use math
movl %cr0,%eax
testl $0x4,%eax # EM (math emulation bit)
je math_state_restore
pushl %ebp
pushl %esi
pushl %edi
call math_emulate
popl %edi
popl %esi
popl %ebp
ret
.align 2
timer_interrupt:
push %ds # save ds,es and put kernel data space
push %es # into them. %fs is used by _system_call
push %fs
pushl %edx # we save %eax,%ecx,%edx as gcc doesn't
pushl %ecx # save those across function calls. %ebx
pushl %ebx # is saved as we use that in ret_sys_call
pushl %eax
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
movl $0x17,%eax
mov %ax,%fs
incl jiffies
movb $0x20,%al # EOI to interrupt controller #1
outb %al,$0x20
movl CS(%esp),%eax
andl $3,%eax # %eax is CPL (0 or 3, 0=supervisor)
pushl %eax
call do_timer # 'do_timer(long CPL)' does everything from
addl $4,%esp # task switching to accounting ...
jmp ret_from_sys_call
.align 2
sys_execve:
lea EIP(%esp),%eax
pushl %eax
call do_execve
addl $4,%esp
ret
.align 2
sys_fork:
call find_empty_process
testl %eax,%eax
js 1f
push %gs
pushl %esi
pushl %edi
pushl %ebp
pushl %eax
call copy_process
addl $20,%esp
1: ret
hd_interrupt:
pushl %eax
pushl %ecx
pushl %edx
push %ds
push %es
push %fs
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
movl $0x17,%eax
mov %ax,%fs
movb $0x20,%al
outb %al,$0xA0 # EOI to interrupt controller #1
jmp 1f # give port chance to breathe
1: jmp 1f
1: xorl %edx,%edx
xchgl do_hd,%edx
testl %edx,%edx
jne 1f
movl $unexpected_hd_interrupt,%edx
1: outb %al,$0x20
call *%edx # "interesting" way of handling intr.
pop %fs
pop %es
pop %ds
popl %edx
popl %ecx
popl %eax
iret
floppy_interrupt:
pushl %eax
pushl %ecx
pushl %edx
push %ds
push %es
push %fs
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
movl $0x17,%eax
mov %ax,%fs
movb $0x20,%al
outb %al,$0x20 # EOI to interrupt controller #1
xorl %eax,%eax
xchgl do_floppy,%eax
testl %eax,%eax
jne 1f
movl $unexpected_floppy_interrupt,%eax
1: call *%eax # "interesting" way of handling intr.
pop %fs
pop %es
pop %ds
popl %edx
popl %ecx
popl %eax
iret
parallel_interrupt:
pushl %eax
movb $0x20,%al
outb %al,$0x20
popl %eax
iret
extern int sys_setup();
extern int sys_exit();
extern int sys_fork();
extern int sys_read();
extern int sys_write();
extern int sys_open();
extern int sys_close();
extern int sys_waitpid();
extern int sys_creat();
extern int sys_link();
extern int sys_unlink();
extern int sys_execve();
extern int sys_chdir();
extern int sys_time();
extern int sys_mknod();
extern int sys_chmod();
extern int sys_chown();
extern int sys_break();
extern int sys_stat();
extern int sys_lseek();
extern int sys_getpid();
extern int sys_mount();
extern int sys_umount();
extern int sys_setuid();
extern int sys_getuid();
extern int sys_stime();
extern int sys_ptrace();
extern int sys_alarm();
extern int sys_fstat();
extern int sys_pause();
extern int sys_utime();
extern int sys_stty();
extern int sys_gtty();
extern int sys_access();
extern int sys_nice();
extern int sys_ftime();
extern int sys_sync();
extern int sys_kill();
extern int sys_rename();
extern int sys_mkdir();
extern int sys_rmdir();
extern int sys_dup();
extern int sys_pipe();
extern int sys_times();
extern int sys_prof();
extern int sys_brk();
extern int sys_setgid();
extern int sys_getgid();
extern int sys_signal();
extern int sys_geteuid();
extern int sys_getegid();
extern int sys_acct();
extern int sys_phys();
extern int sys_lock();
extern int sys_ioctl();
extern int sys_fcntl();
extern int sys_mpx();
extern int sys_setpgid();
extern int sys_ulimit();
extern int sys_uname();
extern int sys_umask();
extern int sys_chroot();
extern int sys_ustat();
extern int sys_dup2();
extern int sys_getppid();
extern int sys_getpgrp();
extern int sys_setsid();
extern int sys_sigaction();
extern int sys_sgetmask();
extern int sys_ssetmask();
extern int sys_setreuid();
extern int sys_setregid();
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_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_wait, sys_sem_post, sys_sem_unlink};
linux-0.11/kernel/makefile 的修改 其实就是把上次的who都换成sem就行了。
#
# Makefile for the FREAX-kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
AR =ar
AS =as --32
LD =ld
LDFLAGS =-m elf_i386 -x
CC =gcc-3.4 -march=i386
CFLAGS =-m32 -g -Wall -O -fstrength-reduce -fomit-frame-pointer \
-finline-functions -nostdinc -I../include
CPP =gcc-3.4 -E -nostdinc -I../include
.c.s:
$(CC) $(CFLAGS) \
-S -o $*.s {1}lt;
.s.o:
$(AS) -o $*.o {1}lt;
.c.o:
$(CC) $(CFLAGS) \
-c -o $*.o {1}lt;
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
kernel.o: $(OBJS)
$(LD) -m elf_i386 -r -o kernel.o $(OBJS)
sync
clean:
rm -f core *.o *.a tmp_make keyboard.s
for i in *.c;do rm -f `basename $i .c`.s;done
(cd chr_drv; make clean)
(cd blk_drv; make clean)
(cd math; make clean)
dep:
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
(for i in *.c;do echo -n `echo $i | sed 's,\.c,\.s,'`" "; \
$(CPP) -M $i;done) >> tmp_make
cp tmp_make Makefile
(cd chr_drv; make dep)
(cd blk_drv; make dep)
### Dependencies:
sem.s sem.o: sem.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
fork.s fork.o: fork.c ../include/errno.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
../include/asm/segment.h ../include/asm/system.h
mktime.s mktime.o: mktime.c ../include/time.h
panic.s panic.o: panic.c ../include/linux/kernel.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
../include/linux/mm.h ../include/signal.h
printk.s printk.o: printk.c ../include/stdarg.h ../include/stddef.h \
../include/linux/kernel.h
sched.s sched.o: sched.c ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
../include/signal.h ../include/linux/kernel.h ../include/linux/sys.h \
../include/linux/fdreg.h ../include/asm/system.h ../include/asm/io.h \
../include/asm/segment.h
signal.s signal.o: signal.c ../include/linux/sched.h ../include/linux/head.h \
../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \
../include/signal.h ../include/linux/kernel.h ../include/asm/segment.h
sys.s sys.o: sys.c ../include/errno.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
../include/linux/mm.h ../include/signal.h ../include/linux/tty.h \
../include/termios.h ../include/linux/kernel.h ../include/asm/segment.h \
../include/sys/times.h ../include/sys/utsname.h
traps.s traps.o: traps.c ../include/string.h ../include/linux/head.h \
../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \
../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \
../include/asm/system.h ../include/asm/segment.h ../include/asm/io.h
vsprintf.s vsprintf.o: vsprintf.c ../include/stdarg.h ../include/string.h
下面开始科普一下中诶实验用到的知识
(1)对信号量操作的PV原语:
P原语操作的动作是:
(1)S减1;
(2)若S减1后仍大于或等于零,则进程继续执行;
(3)若S减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转进程调度。
V原语操作的动作是:
(1)S加1;
(2)若相加结果大于零,则进程继续执行;
(3)若相加结果小于或等于零,则从该信号的等待队列中唤醒一等待进程,然后再返回原进程继续执行或转进程调度。
PV操作对于每一个进程来说,都只能进行一次,而且必须成对使用。在PV原语执行期间不允许有中断的发生。
PV 源语执行期间不允许有中断这句话很重要,在写cem.c的时候要使用开中断关中断来实现。
(2)cli 与 sti函数
cli 禁止中断发生
sti 允许中断发生
在对 ss 和sp操作的时候, 如果有中断发生,中断的保存现场的操作是将相关寄存器值保存到ss:sp指向的地址.
如果ss 或者sp没有完成赋值操作, 这时候ss:sp指向的地址则是不期望的地方. 如果将系统或者其他应用的数据覆盖,会导致系统/应用崩溃.
(3)系统调用 schedule()
它会唤醒当前等待进程中优先级最高的进程,sem_wait()需要用他实现。
吧state设为TASK_UNINTERRUPTIBLE再调用schedule()让系统处理其他的事
sem_post()中只要吧state设为 running 可运行态,然后让系统自己去分配去就行了。
(4)文本文件与二进开文件
fopen提供wt与wb两种打开参数,fwrite是以二进制写数据,以文本方式打开是不可读的。并且换行符'\n'会被解析成两个字符 0x0D 0x0A,
因为是作为缓冲区pc.c用到了wb这种打开方式。
(5)进程之间共享数据
pcc中使用了把需要共享的数据写到,文件缓冲区中来达到进程间共享数据的目的。
(6)函数的查询
有一些函数可以在linux手册中查询 比如 man fopen
(7)0.11 中的终端输出问题
0.11 输出有问题,看结果的话可以重定向到文件来看 ./pc > a.txt
或者让它慢慢显示 ./pc | more
(8) 实验指导书中失效的链接
喜欢E文的同学可以看看 http://linux.die.net/man/7/sem_overview
(9) PCB结构
在linux中每一个进程都通过一个叫做task_struck的数据结构来定义,也就是PCB,fork时,系统会自动产生一个task_struct结构,从父进程里
继承一些数据,然后被插入到进程树中。
/include/linux/sched.h可以找到task_struct 的定义。
在sem.c中我们主要通过修改这个结沟中的state来改变进程的状态。
(10) 临界区
系统中需要被多个进程访问,但同时中能被一个进程访问的共用数据。
(11)死锁
多个进程因互相争夺资源而互相等待的现象,无外力干预就会一直持续。
可以在本地运行的代码,有关POSIX thread的程序在编辑时要链接,thread库
用gcc -o pc pc.c -lpthread -Wall 就可以了
0.11下编译是不许要加 -lpthread 因为他根本没这个库 - -!
这个很简单就不做解释了,只需要说明一点,所有的消费者需要共享get_pos这个变量,来确定需要取文件缓冲区的那个位置的数据,这个变量写在文件缓冲区的第11个位置。
#define __LIBRARY__
#include
#include
#include
#include
#include
#include
#include
int input_num(FILE* fp, int put_pos,int num){
fseek( fp, put_pos*sizeof(int) , SEEK_SET );
int run_code=fwrite( &num, 1, sizeof(num), fp);
fflush(fp);
return run_code;
}
int output_num(FILE* fp, int get_pos,int* num){
fseek( fp, get_pos*sizeof(int) , SEEK_SET );
return fread( num, sizeof(int),1, fp);
}
int main()
{
int const NUM=100;
int const PRONUM=5;
int const MAXSIZE=10;
int i,j,k;
int cost_num;
int get_pos = 0;
int put_pos = 0;
sem_t *empty, *full, *mutex;
FILE *fp = NULL;
empty =(sem_t *)sem_open("empty",O_CREAT,0064,10);
full = (sem_t *)sem_open("full",O_CREAT,0064,0);
mutex = (sem_t *)sem_open("mutex",O_CREAT,0064,1);
fp=fopen("filebuffer.txt", "wb+");
input_num(fp,10,get_pos);
if( !fork() )
{
for( i = 0 ; i < NUM; i++)
{
sem_wait(empty);
sem_wait(mutex);
input_num(fp,put_pos,i);
put_pos = ( put_pos + 1)% MAXSIZE;
sem_post(mutex);
sem_post(full);
}
exit(0);
}
for( k = 0; k < PRONUM ; k++ )
{
if( !fork() )
{
for( j = 0; j < NUM/PRONUM; j++ )
{
sem_wait(full);
sem_wait(mutex);
fflush(stdout);
output_num(fp,10,&get_pos);
output_num(fp,get_pos,&cost_num);
printf("%d: %d\n",getpid(),cost_num);
fflush(stdout);
get_pos = (get_pos + 1) % MAXSIZE;
input_num(fp,10,get_pos);
sem_post(mutex);
sem_post(empty);
}
exit(0);
}
}
wait(NULL);
sem_unlink("empty");
sem_unlink("full");
sem_unlink("mutex");
fclose(fp);
return 0;
}
在0.11上可以执行的代码
把系统调用的宏加上,再吧sem_open的参数改一下就可以了。
#define __LIBRARY__
#include
#include
#include
#include
#include
#include
_syscall2(int,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)
static int st = 0;
int input_num(FILE* fp, int put_pos,int num){
int run_code;
fseek( fp, put_pos*sizeof(int) , SEEK_SET );
run_code=fwrite( &num, 1, sizeof(num), fp);
fflush(fp);
return run_code;
}
int output_num(FILE* fp, int get_pos,int* num){
fseek( fp, get_pos*sizeof(int) , SEEK_SET );
return fread( num, sizeof(int),1, fp);
}
int main()
{
int const NUM=500;
int const PRONUM=5;
int const MAXSIZE=10;
int i,j,k;
int cost_num;
int get_pos = 0;
int put_pos = 0;
sem_t *empty, *full, *mutex;
FILE *fp = NULL;
empty =(sem_t *)sem_open("empty",10);
full = (sem_t *)sem_open("full",0);
mutex = (sem_t *)sem_open("mutex",1);
fp=fopen("/var/buffer.txt", "wb+");
input_num(fp,10,get_pos);
if( !fork() )
{
for( i = 0 ; i < NUM; i++)
{
sem_wait(empty);
sem_wait(mutex);
input_num(fp,put_pos,i);
put_pos = ( put_pos + 1)% MAXSIZE;
sem_post(mutex);
sem_post(full);
}
exit(0);
}
for( k = 0; k < PRONUM ; k++ )
{
if( !fork() )
{
for( j = 0; j < NUM/PRONUM; j++ )
{
sem_wait(full);
sem_wait(mutex);
fflush(stdout);
output_num(fp,10,&get_pos);
output_num(fp,get_pos,&cost_num);
printf("%d: %d\n",getpid(),cost_num);
fflush(stdout);
get_pos = (get_pos + 1) % MAXSIZE;
input_num(fp,10,get_pos);
sem_post(mutex);
sem_post(empty);
}
exit(0);
}
}
wait(NULL);
sem_unlink("empty");
sem_unlink("full");
sem_unlink("mutex");
fclose(fp);
return 0;
}
sem.c的代码如下,因为确实比较难写,我就抄了抄网上的代码。
需要吧数据结构的定义放到 虚拟机的user/include/unistd.h 下再包含unistd.h,这是比较牛逼的写法(上文提供的unistd.h没有包含结构体的定义)
思路是每个sem_t中包含一个循环队列,
队列中存着在当前信号量下等待的进程,
每当Sem_wait被调用且满足要求时,当前进程中断并进入队尾。
sem_post被调用且条件成立时,队头进程被唤醒。
#define Maxlength 10
struct queue
{
int front;
int rear;
struct task_struct *wait[Maxlength];
};
typedef struct queue queue;
struct sem_t
{
int value;
int used;
struct queue waitsem;
};
typedef struct sem_t sem_t;
#define __LIBRARY__
#include
#include
#include
#include
#include
#include
const int SEM_NUM=20;
char sem_name[20][20] = {};
sem_t sem_array[20];
int find_sem(char* name){
int i;
for(i = 0;i < SEM_NUM; i++)
{
if(!strcmp(sem_name[i],name))
{
return i;
}
}
return -1;
}
char* get_name(const char* name){
char tempname[20]={};
char temp;
int i=0;
while((temp = get_fs_byte(name+i))!='\0')
{
tempname[i] = temp;
i++;
}
tempname[i]='\0';
return tempname;
}
int next(int i)
{
return (i+1==Maxlength)?0:i+1;
}
void initQue(queue * q)
{
q->front = 0;
q->rear = Maxlength - 1;
}
int empty(queue* q)
{
if(next(q->rear) == q->front ){
printk("isempty\n");
return 1;
}
else
return 0;
}
int isFull(queue* q)
{
if(q->front==(q->rear+2)%Maxlength){
printk("ifFull,%d %d\n",q->front,q->rear);
return 1;
}
else
return 0;
}
struct task_struct * getFront( queue * q )
{
int temp;
if( !empty(q) )
{
temp = q->front;
q->front = next( q->front );
return q->wait[temp];
}
else
return NULL;
}
int insertRear( struct task_struct * child, queue * q)
{
if(isFull(q))
return -1;
q->rear = next( q->rear );
q->wait[q->rear] = child;
}
void sleep_on_sem(void)
{
current->state=TASK_UNINTERRUPTIBLE;
schedule();
}
void wake_on_sem(struct task_struct *p)
{
if(p != NULL)
(*p).state = TASK_RUNNING;
}
int sys_sem_open(const char *name, unsigned int value)
{
int i = 0;
char* tempname = malloc(sizeof(char)*20);
tempname=get_name(name);
if (!(i=find_sem(tempname))){
return &sem_array[i];
}
for (i = 0; i < SEM_NUM; i++)
{
if (!sem_array[i].used)
{
strcpy(sem_name[i],tempname);
sem_array[i].value = value;
sem_array[i].used = 1;
initQue( &(sem_array[i].waitsem));
return &sem_array[i];
}
}
return -1;
}
int sys_sem_wait(sem_t* sem)
{
cli();
sem->value--;
if(sem->value < 0)
{
insertRear( current, &(sem->waitsem));
sleep_on_sem();
}
sti();
return 0;
}
int sys_sem_post(sem_t * sem)
{
cli();
sem->value++;
if(sem->value<=0)
{
wake_on_sem(getFront(&(sem->waitsem)));
}
sti();
return 0;
}
int sys_sem_unlink(const char *name)
{
int locate = 0;
char* tempname = malloc(sizeof(char)*20);
tempname=get_name(name);
if (!(locate=find_sem(tempname))){
sem_array[locate].used = 0;
sem_array[locate].value = 0;
sem_name[locate][0] = '\0';
return 0;
}
return -1;
}
喵喵~
最后给大家推荐一个漫画家的博客
http://wc31415.blogcn.com/