int dup(int oldfd)
主要涉及到3张表的操作:进程打开文件表、系统打开文件表和内存索引节点表。
首先,进程打开文件表是进程U区的一部分,U区的结构如下:
struct user {
struct pcb u_pcb;
struct proc *u_procp; /* pointer to proc structure */
int *u_ar0; /* address of users saved R0 */
char u_comm[MAXNAMLEN + 1];
/* syscall parameters, results and catches */
int u_arg[8]; /* arguments to current system call */
int *u_ap; /* pointer to arglist */
label_t u_qsave; /* for non-local gotos on interrupts */
char u_error; /* return error code */
union { /* syscall return values */
struct {
int R_val1;
int R_val2;
} u_rv;
#define r_val1 u_rv.R_val1
#define r_val2 u_rv.R_val2
off_t r_off;
time_t r_time;
} u_r;
char u_eosys; /* special action on end of syscall */
/* 1.1 - processes and protection */
short u_uid; /* effective user id */
short u_gid; /* effective group id */
int u_groups[NGROUPS]; /* groups, 0 terminated */
short u_ruid; /* real user id */
short u_rgid; /* real group id */
/* 1.2 - memory management */
size_t u_tsize; /* text size (clicks) */
size_t u_dsize; /* data size (clicks) */
size_t u_ssize; /* stack size (clicks) */
struct dmap u_dmap; /* disk map for data segment */
struct dmap u_smap; /* disk map for stack segment */
struct dmap u_cdmap, u_csmap; /* shadows of u_dmap, u_smap, for
use of parent during fork */
label_t u_ssave; /* label variable for swapping */
size_t u_odsize, u_ossize; /* for (clumsy) expansion swaps */
time_t u_outime; /* user time at last sample */
/* 1.3 - signal management */
int (*u_signal[NSIG])(); /* disposition of signals */
int u_sigmask[NSIG]; /* signals to be blocked */
int u_sigonstack; /* signals to take on sigstack */
int u_oldmask; /* saved mask from before sigpause */
int u_code; /* ``code'' to trap */
struct sigstack u_sigstack; /* sp & on stack state variable */
#define u_onstack u_sigstack.ss_onstack
#define u_sigsp u_sigstack.ss_sp
/* 1.4 - descriptor management */
struct file *u_ofile[NOFILE]; /* file structures for open files */
char u_pofile[NOFILE]; /* per-process flags of open files */
#define UF_EXCLOSE 0x1 /* auto-close on exec */
#define UF_MAPPED 0x2 /* mapped from device */
struct inode *u_cdir; /* current directory */
struct inode *u_rdir; /* root directory of current process */
struct tty *u_ttyp; /* controlling tty pointer */
dev_t u_ttyd; /* controlling tty dev */
short u_cmask; /* mask for file creation */
/* 1.5 - timing and statistics */
struct rusage u_ru; /* stats for this proc */
struct rusage u_cru; /* sum of stats for reaped children */
struct itimerval u_timer[3];
int u_XXX[3];
time_t u_start;
short u_acflag;
/* 1.6 - resource controls */
struct rlimit u_rlimit[RLIM_NLIMITS];
struct quota *u_quota; /* user's quota structure */
int u_qflags; /* per process quota flags */
/* BEGIN TRASH */
char u_segflg; /* 0:user D; 1:system; 2:user I */
caddr_t u_base; /* base address for IO */
unsigned int u_count; /* bytes remaining for IO */
off_t u_offset; /* offset in file for IO */
union {
struct { /* header of executable file */
int Ux_mag; /* magic number */
unsigned Ux_tsize; /* text size */
unsigned Ux_dsize; /* data size */
unsigned Ux_bsize; /* bss size */
unsigned Ux_ssize; /* symbol table size */
unsigned Ux_entloc; /* entry location */
unsigned Ux_unused;
unsigned Ux_relflg;
} Ux_A;
char ux_shell[SHSIZE]; /* #! and name of interpreter */
} u_exdata;
进程打开文件表的结构如下:
/*
* Descriptor table entry.
* One for each kernel object.
*/
struct file {
int f_flag; /* see below */
short f_type; /* descriptor type */
short f_count; /* reference count */
short f_msgcount; /* references from message queue */
struct fileops {
int (*fo_rw)();
int (*fo_ioctl)();
int (*fo_select)();
int (*fo_close)();
} *f_ops;
caddr_t f_data; /* inode 类似于 struct inode *f_uinode;参考: svr2*/
off_t f_offset;
};
extern struct file file[]; /*The file table itself 参考: svr2*/
内存索引节点表结构如下:
struct inode {
struct inode *i_chain[2]; /* must be first */
u_short i_flag;
u_short i_count; /* reference count */
dev_t i_dev; /* device where inode resides */
u_short i_shlockc; /* count of shared locks on inode */
u_short i_exlockc; /* count of exclusive locks on inode */
ino_t i_number; /* i number, 1-to-1 with device address */
struct fs *i_fs; /* file sys associated with this inode */
struct dquot *i_dquot; /* quota structure controlling this file */
union {
daddr_t if_lastr; /* last read (read-ahead) */
struct socket *is_socket;
struct {
struct inode *if_freef; /* free list forward */
struct inode **if_freeb; /* free list back */
} i_fr;
} i_un;
struct icommon
{
u_short ic_mode; /* 0: mode and type of file */
short ic_nlink; /* 2: number of links to file */
short ic_uid; /* 4: owner's user id */
short ic_gid; /* 6: owner's group id */
quad ic_size; /* 8: number of bytes in file */
time_t ic_atime; /* 16: time last accessed */
long ic_atspare;
time_t ic_mtime; /* 24: time last modified */
long ic_mtspare;
time_t ic_ctime; /* 32: last time inode changed */
long ic_ctspare;
daddr_t ic_db[NDADDR]; /* 40: disk block addresses */
daddr_t ic_ib[NIADDR]; /* 88: indirect blocks */
long ic_flags; /* 100: status, currently unused */
long ic_blocks; /* 104: blocks actually held */
long ic_spare[5]; /* 108: reserved, currently unused */
} i_ic;
};
extern struct inode inode[];/*The inode table itself 参考: svr2*/
最后我们看dup的代码:
dup()
{
register struct a {
int i;
} *uap = (struct a *) u.u_ap;/*存储参数地方*/
struct file *fp;
int j;
if (uap->i &~ 077) { uap->i &= 077; dup2(); return; } /* XXX */
fp = getf(uap->i);/*得到该文件描述所指向的系统活动文件表项*/
if (fp == 0)
return;
j = ufalloc(0);/*找到进程打开文件表中最小的空闲项*/
if (j < 0)
return;
dupit(j, fp, u.u_pofile[uap->i]);/*使找到空闲项指向指定的文件表项*/
}
/
/*
* Convert a user supplied file descriptor into a pointer
* to a file structure. Only task is to check range of the descriptor.
* Critical paths should use the GETF macro.
*/
struct file *
getf(f)
register int f;
{
register struct file *fp;
if ((unsigned)f >= NOFILE || (fp = u.u_ofile[f]) == NULL) {
u.u_error = EBADF;
return (NULL);
}
return (fp);
}
/*
* Allocate a user file descriptor.
*/
ufalloc(i)
register int i;
{
for (; i < NOFILE; i++)
if (u.u_ofile[i] == NULL) {
u.u_r.r_val1 = i;
u.u_pofile[i] = 0;
return (i);
}
u.u_error = EMFILE;
return (-1);
}
/
dupit(fd, fp, flags)
int fd;
register struct file *fp;
register int flags;
{
u.u_ofile[fd] = fp;
u.u_pofile[fd] = flags;
fp->f_count++;
}
主要涉及到3张表的操作:进程打开文件表、系统打开文件表和内存索引节点表。
首先,进程打开文件表是进程U区的一部分,U区的结构如下:
struct user {
struct pcb u_pcb;
struct proc *u_procp; /* pointer to proc structure */
int *u_ar0; /* address of users saved R0 */
char u_comm[MAXNAMLEN + 1];
/* syscall parameters, results and catches */
int u_arg[8]; /* arguments to current system call */
int *u_ap; /* pointer to arglist */
label_t u_qsave; /* for non-local gotos on interrupts */
char u_error; /* return error code */
union { /* syscall return values */
struct {
int R_val1;
int R_val2;
} u_rv;
#define r_val1 u_rv.R_val1
#define r_val2 u_rv.R_val2
off_t r_off;
time_t r_time;
} u_r;
char u_eosys; /* special action on end of syscall */
/* 1.1 - processes and protection */
short u_uid; /* effective user id */
short u_gid; /* effective group id */
int u_groups[NGROUPS]; /* groups, 0 terminated */
short u_ruid; /* real user id */
short u_rgid; /* real group id */
/* 1.2 - memory management */
size_t u_tsize; /* text size (clicks) */
size_t u_dsize; /* data size (clicks) */
size_t u_ssize; /* stack size (clicks) */
struct dmap u_dmap; /* disk map for data segment */
struct dmap u_smap; /* disk map for stack segment */
struct dmap u_cdmap, u_csmap; /* shadows of u_dmap, u_smap, for
use of parent during fork */
label_t u_ssave; /* label variable for swapping */
size_t u_odsize, u_ossize; /* for (clumsy) expansion swaps */
time_t u_outime; /* user time at last sample */
/* 1.3 - signal management */
int (*u_signal[NSIG])(); /* disposition of signals */
int u_sigmask[NSIG]; /* signals to be blocked */
int u_sigonstack; /* signals to take on sigstack */
int u_oldmask; /* saved mask from before sigpause */
int u_code; /* ``code'' to trap */
struct sigstack u_sigstack; /* sp & on stack state variable */
#define u_onstack u_sigstack.ss_onstack
#define u_sigsp u_sigstack.ss_sp
/* 1.4 - descriptor management */
struct file *u_ofile[NOFILE]; /* file structures for open files */
char u_pofile[NOFILE]; /* per-process flags of open files */
#define UF_EXCLOSE 0x1 /* auto-close on exec */
#define UF_MAPPED 0x2 /* mapped from device */
struct inode *u_cdir; /* current directory */
struct inode *u_rdir; /* root directory of current process */
struct tty *u_ttyp; /* controlling tty pointer */
dev_t u_ttyd; /* controlling tty dev */
short u_cmask; /* mask for file creation */
/* 1.5 - timing and statistics */
struct rusage u_ru; /* stats for this proc */
struct rusage u_cru; /* sum of stats for reaped children */
struct itimerval u_timer[3];
int u_XXX[3];
time_t u_start;
short u_acflag;
/* 1.6 - resource controls */
struct rlimit u_rlimit[RLIM_NLIMITS];
struct quota *u_quota; /* user's quota structure */
int u_qflags; /* per process quota flags */
/* BEGIN TRASH */
char u_segflg; /* 0:user D; 1:system; 2:user I */
caddr_t u_base; /* base address for IO */
unsigned int u_count; /* bytes remaining for IO */
off_t u_offset; /* offset in file for IO */
union {
struct { /* header of executable file */
int Ux_mag; /* magic number */
unsigned Ux_tsize; /* text size */
unsigned Ux_dsize; /* data size */
unsigned Ux_bsize; /* bss size */
unsigned Ux_ssize; /* symbol table size */
unsigned Ux_entloc; /* entry location */
unsigned Ux_unused;
unsigned Ux_relflg;
} Ux_A;
char ux_shell[SHSIZE]; /* #! and name of interpreter */
} u_exdata;
进程打开文件表的结构如下:
/*
* Descriptor table entry.
* One for each kernel object.
*/
struct file {
int f_flag; /* see below */
short f_type; /* descriptor type */
short f_count; /* reference count */
short f_msgcount; /* references from message queue */
struct fileops {
int (*fo_rw)();
int (*fo_ioctl)();
int (*fo_select)();
int (*fo_close)();
} *f_ops;
caddr_t f_data; /* inode 类似于 struct inode *f_uinode;参考: svr2*/
off_t f_offset;
};
extern struct file file[]; /*The file table itself 参考: svr2*/
内存索引节点表结构如下:
struct inode {
struct inode *i_chain[2]; /* must be first */
u_short i_flag;
u_short i_count; /* reference count */
dev_t i_dev; /* device where inode resides */
u_short i_shlockc; /* count of shared locks on inode */
u_short i_exlockc; /* count of exclusive locks on inode */
ino_t i_number; /* i number, 1-to-1 with device address */
struct fs *i_fs; /* file sys associated with this inode */
struct dquot *i_dquot; /* quota structure controlling this file */
union {
daddr_t if_lastr; /* last read (read-ahead) */
struct socket *is_socket;
struct {
struct inode *if_freef; /* free list forward */
struct inode **if_freeb; /* free list back */
} i_fr;
} i_un;
struct icommon
{
u_short ic_mode; /* 0: mode and type of file */
short ic_nlink; /* 2: number of links to file */
short ic_uid; /* 4: owner's user id */
short ic_gid; /* 6: owner's group id */
quad ic_size; /* 8: number of bytes in file */
time_t ic_atime; /* 16: time last accessed */
long ic_atspare;
time_t ic_mtime; /* 24: time last modified */
long ic_mtspare;
time_t ic_ctime; /* 32: last time inode changed */
long ic_ctspare;
daddr_t ic_db[NDADDR]; /* 40: disk block addresses */
daddr_t ic_ib[NIADDR]; /* 88: indirect blocks */
long ic_flags; /* 100: status, currently unused */
long ic_blocks; /* 104: blocks actually held */
long ic_spare[5]; /* 108: reserved, currently unused */
} i_ic;
};
extern struct inode inode[];/*The inode table itself 参考: svr2*/
最后我们看dup的代码:
dup()
{
register struct a {
int i;
} *uap = (struct a *) u.u_ap;/*存储参数地方*/
struct file *fp;
int j;
if (uap->i &~ 077) { uap->i &= 077; dup2(); return; } /* XXX */
fp = getf(uap->i);/*得到该文件描述所指向的系统活动文件表项*/
if (fp == 0)
return;
j = ufalloc(0);/*找到进程打开文件表中最小的空闲项*/
if (j < 0)
return;
dupit(j, fp, u.u_pofile[uap->i]);/*使找到空闲项指向指定的文件表项*/
}
/
/*
* Convert a user supplied file descriptor into a pointer
* to a file structure. Only task is to check range of the descriptor.
* Critical paths should use the GETF macro.
*/
struct file *
getf(f)
register int f;
{
register struct file *fp;
if ((unsigned)f >= NOFILE || (fp = u.u_ofile[f]) == NULL) {
u.u_error = EBADF;
return (NULL);
}
return (fp);
}
/*
* Allocate a user file descriptor.
*/
ufalloc(i)
register int i;
{
for (; i < NOFILE; i++)
if (u.u_ofile[i] == NULL) {
u.u_r.r_val1 = i;
u.u_pofile[i] = 0;
return (i);
}
u.u_error = EMFILE;
return (-1);
}
/
dupit(fd, fp, flags)
int fd;
register struct file *fp;
register int flags;
{
u.u_ofile[fd] = fp;
u.u_pofile[fd] = flags;
fp->f_count++;
}