📄 exec.c
字号:
/* Allocate new memory and release the old memory. Change the map and report * the new map to the kernel. Zero the new core image's bss, gap and stack. */ register struct mproc *rmp = mp; vir_clicks text_clicks, data_clicks, gap_clicks, stack_clicks, tot_clicks; phys_clicks new_base; phys_bytes bytes, base, bss_offset; int s; /* No need to allocate text if it can be shared. */ if (sh_mp != NULL) text_bytes = 0; /* Allow the old data to be swapped out to make room. (Which is really a * waste of time, because we are going to throw it away anyway.) */ rmp->mp_flags |= WAITING; /* Acquire the new memory. Each of the 4 parts: text, (data+bss), gap, * and stack occupies an integral number of clicks, starting at click * boundary. The data and bss parts are run together with no space. */ text_clicks = ((unsigned long) text_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; data_clicks = (data_bytes + bss_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; stack_clicks = (stk_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; tot_clicks = (tot_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; gap_clicks = tot_clicks - data_clicks - stack_clicks; if ( (int) gap_clicks < 0) return(ENOMEM); /* Try to allocate memory for the new process. */ new_base = alloc_mem(text_clicks + tot_clicks); if (new_base == NO_MEM) return(ENOMEM); /* We've got memory for the new core image. Release the old one. */ rmp = mp; if (find_share(rmp, rmp->mp_ino, rmp->mp_dev, rmp->mp_ctime) == NULL) { /* No other process shares the text segment, so free it. */ free_mem(rmp->mp_seg[T].mem_phys, rmp->mp_seg[T].mem_len); } /* Free the data and stack segments. */ free_mem(rmp->mp_seg[D].mem_phys, rmp->mp_seg[S].mem_vir + rmp->mp_seg[S].mem_len - rmp->mp_seg[D].mem_vir); /* We have now passed the point of no return. The old core image has been * forever lost, memory for a new core image has been allocated. Set up * and report new map. */ if (sh_mp != NULL) { /* Share the text segment. */ rmp->mp_seg[T] = sh_mp->mp_seg[T]; } else { rmp->mp_seg[T].mem_phys = new_base; rmp->mp_seg[T].mem_vir = 0; rmp->mp_seg[T].mem_len = text_clicks; } rmp->mp_seg[D].mem_phys = new_base + text_clicks; rmp->mp_seg[D].mem_vir = 0; rmp->mp_seg[D].mem_len = data_clicks; rmp->mp_seg[S].mem_phys = rmp->mp_seg[D].mem_phys + data_clicks + gap_clicks; rmp->mp_seg[S].mem_vir = rmp->mp_seg[D].mem_vir + data_clicks + gap_clicks; rmp->mp_seg[S].mem_len = stack_clicks;#if (CHIP == M68000) rmp->mp_seg[T].mem_vir = 0; rmp->mp_seg[D].mem_vir = rmp->mp_seg[T].mem_len; rmp->mp_seg[S].mem_vir = rmp->mp_seg[D].mem_vir + rmp->mp_seg[D].mem_len + gap_clicks;#endif sys_newmap(who, rmp->mp_seg); /* report new map to the kernel */ /* The old memory may have been swapped out, but the new memory is real. */ rmp->mp_flags &= ~(WAITING|ONSWAP|SWAPIN); /* Zero the bss, gap, and stack segment. */ bytes = (phys_bytes)(data_clicks + gap_clicks + stack_clicks) << CLICK_SHIFT; base = (phys_bytes) rmp->mp_seg[D].mem_phys << CLICK_SHIFT; bss_offset = (data_bytes >> CLICK_SHIFT) << CLICK_SHIFT; base += bss_offset; bytes -= bss_offset; if ((s=sys_memset(0, base, bytes)) != OK) { panic(__FILE__,"new_mem can't zero", s); } return(OK);}/*===========================================================================* * patch_ptr * *===========================================================================*/PRIVATE void patch_ptr(stack, base)char stack[ARG_MAX]; /* pointer to stack image within PM */vir_bytes base; /* virtual address of stack base inside user */{/* When doing an exec(name, argv, envp) call, the user builds up a stack * image with arg and env pointers relative to the start of the stack. Now * these pointers must be relocated, since the stack is not positioned at * address 0 in the user's address space. */ char **ap, flag; vir_bytes v; flag = 0; /* counts number of 0-pointers seen */ ap = (char **) stack; /* points initially to 'nargs' */ ap++; /* now points to argv[0] */ while (flag < 2) { if (ap >= (char **) &stack[ARG_MAX]) return; /* too bad */ if (*ap != NULL) { v = (vir_bytes) *ap; /* v is relative pointer */ v += base; /* relocate it */ *ap = (char *) v; /* put it back */ } else { flag++; } ap++; }}/*===========================================================================* * insert_arg * *===========================================================================*/PRIVATE int insert_arg(stack, stk_bytes, arg, replace)char stack[ARG_MAX]; /* pointer to stack image within PM */vir_bytes *stk_bytes; /* size of initial stack */char *arg; /* argument to prepend/replace as new argv[0] */int replace;{/* Patch the stack so that arg will become argv[0]. Be careful, the stack may * be filled with garbage, although it normally looks like this: * nargs argv[0] ... argv[nargs-1] NULL envp[0] ... NULL * followed by the strings "pointed" to by the argv[i] and the envp[i]. The * pointers are really offsets from the start of stack. * Return true iff the operation succeeded. */ int offset, a0, a1, old_bytes = *stk_bytes; /* Prepending arg adds at least one string and a zero byte. */ offset = strlen(arg) + 1; a0 = (int) ((char **) stack)[1]; /* argv[0] */ if (a0 < 4 * PTRSIZE || a0 >= old_bytes) return(FALSE); a1 = a0; /* a1 will point to the strings to be moved */ if (replace) { /* Move a1 to the end of argv[0][] (argv[1] if nargs > 1). */ do { if (a1 == old_bytes) return(FALSE); --offset; } while (stack[a1++] != 0); } else { offset += PTRSIZE; /* new argv[0] needs new pointer in argv[] */ a0 += PTRSIZE; /* location of new argv[0][]. */ } /* stack will grow by offset bytes (or shrink by -offset bytes) */ if ((*stk_bytes += offset) > ARG_MAX) return(FALSE); /* Reposition the strings by offset bytes */ memmove(stack + a1 + offset, stack + a1, old_bytes - a1); strcpy(stack + a0, arg); /* Put arg in the new space. */ if (!replace) { /* Make space for a new argv[0]. */ memmove(stack + 2 * PTRSIZE, stack + 1 * PTRSIZE, a0 - 2 * PTRSIZE); ((char **) stack)[0]++; /* nargs++; */ } /* Now patch up argv[] and envp[] by offset. */ patch_ptr(stack, (vir_bytes) offset); ((char **) stack)[1] = (char *) a0; /* set argv[0] correctly */ return(TRUE);}/*===========================================================================* * patch_stack * *===========================================================================*/PRIVATE char *patch_stack(fd, stack, stk_bytes, script)int fd; /* file descriptor to open script file */char stack[ARG_MAX]; /* pointer to stack image within PM */vir_bytes *stk_bytes; /* size of initial stack */char *script; /* name of script to interpret */{/* Patch the argument vector to include the path name of the script to be * interpreted, and all strings on the #! line. Returns the path name of * the interpreter. */ char *sp, *interp = NULL; int n; enum { INSERT=FALSE, REPLACE=TRUE }; /* Make script[] the new argv[0]. */ if (!insert_arg(stack, stk_bytes, script, REPLACE)) return(NULL); if (lseek(fd, 2L, 0) == -1 /* just behind the #! */ || (n= read(fd, script, PATH_MAX)) < 0 /* read line one */ || (sp= memchr(script, '\n', n)) == NULL) /* must be a proper line */ return(NULL); /* Move sp backwards through script[], prepending each string to stack. */ for (;;) { /* skip spaces behind argument. */ while (sp > script && (*--sp == ' ' || *sp == '\t')) {} if (sp == script) break; sp[1] = 0; /* Move to the start of the argument. */ while (sp > script && sp[-1] != ' ' && sp[-1] != '\t') --sp; interp = sp; if (!insert_arg(stack, stk_bytes, sp, INSERT)) return(NULL); } /* Round *stk_bytes up to the size of a pointer for alignment contraints. */ *stk_bytes= ((*stk_bytes + PTRSIZE - 1) / PTRSIZE) * PTRSIZE; close(fd); return(interp);}/*===========================================================================* * rw_seg * *===========================================================================*/PUBLIC void rw_seg(rw, fd, proc, seg, seg_bytes0)int rw; /* 0 = read, 1 = write */int fd; /* file descriptor to read from / write to */int proc; /* process number */int seg; /* T, D, or S */phys_bytes seg_bytes0; /* how much is to be transferred? */{/* Transfer text or data from/to a file and copy to/from a process segment. * This procedure is a little bit tricky. The logical way to transfer a * segment would be block by block and copying each block to/from the user * space one at a time. This is too slow, so we do something dirty here, * namely send the user space and virtual address to the file system in the * upper 10 bits of the file descriptor, and pass it the user virtual address * instead of a PM address. The file system extracts these parameters when * gets a read or write call from the process manager, which is the only * process that is permitted to use this trick. The file system then copies * the whole segment directly to/from user space, bypassing PM completely. * * The byte count on read is usually smaller than the segment count, because * a segment is padded out to a click multiple, and the data segment is only * partially initialized. */ int new_fd, bytes, r; char *ubuf_ptr; struct mem_map *sp = &mproc[proc].mp_seg[seg]; phys_bytes seg_bytes = seg_bytes0; new_fd = (proc << 7) | (seg << 5) | fd; ubuf_ptr = (char *) ((vir_bytes) sp->mem_vir << CLICK_SHIFT); while (seg_bytes != 0) {#define PM_CHUNK_SIZE 8192 bytes = MIN((INT_MAX / PM_CHUNK_SIZE) * PM_CHUNK_SIZE, seg_bytes); if (rw == 0) { r = read(new_fd, ubuf_ptr, bytes); } else { r = write(new_fd, ubuf_ptr, bytes); } if (r != bytes) break; ubuf_ptr += bytes; seg_bytes -= bytes; }}/*===========================================================================* * find_share * *===========================================================================*/PUBLIC struct mproc *find_share(mp_ign, ino, dev, ctime)struct mproc *mp_ign; /* process that should not be looked at */ino_t ino; /* parameters that uniquely identify a file */dev_t dev;time_t ctime;{/* Look for a process that is the file <ino, dev, ctime> in execution. Don't * accidentally "find" mp_ign, because it is the process on whose behalf this * call is made. */ struct mproc *sh_mp; for (sh_mp = &mproc[0]; sh_mp < &mproc[NR_PROCS]; sh_mp++) { if (!(sh_mp->mp_flags & SEPARATE)) continue; if (sh_mp == mp_ign) continue; if (sh_mp->mp_ino != ino) continue; if (sh_mp->mp_dev != dev) continue; if (sh_mp->mp_ctime != ctime) continue; return sh_mp; } return(NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -