Ver a proveniência

上传文件至 ''

master
郭腾 há 3 anos
ascendente
cometimento
858a99df24
4 ficheiros alterados com 1525 adições e 0 eliminações
  1. +77
    -0
      README.md
  2. +456
    -0
      bits.c
  3. +333
    -0
      mm.c
  4. +659
    -0
      tsh.c

+ 77
- 0
README.md Ver ficheiro

@ -0,0 +1,77 @@
Datalab: bits.c
Malloclab: mm.c
Shelllab: tsh.c
Malloc Lab
before uploaded to gitlab, mark the progress in ucloud.
(it seems that it cannot work in my own lxc)
write the code with the help of CSAPP and its code.
downloaded some trace file from github
saved in ./traces
./mdriver -a -g -v -t traces/ to autograde.
deal with some bugs with blogs.
2020/12/24-25:
design the structure of heap with the help of CSAPP
2020/12/26:
write some helpful micros and functions with the help of CSAPP
start to write mm_init and mm_malloc, but it's not tested
2020/12/27:
test mm_init,mm_malloc and debug
start to write mm_free
2020/12/28:
test mm_free and debug
write some part of mm_realloc
2020/12/29:
test mm_realloc and debug
total autograded and modify heap
2020/12/30-31:
code modified with some blogs:
1.deal with some heap errors
2.adjust some expression to make codes simplier
3.intensify the limitation of helper function
4.modify some function and variable name
5.complete the micros
annotation completed with the help of CSAPP
upload to ucloud and gitlab
2021/1/19-20(Modification start):
1.plan to use explict list instead of implict list.
2.add some micros and edit mm_init.
2021/1/21-22:
1.edit mm_malloc and some related func.
2021/1/23:
1.final modification, with some helpful imformation from blogs.
Shell Lab
2021/1/19:
1.start to design func with the help of CSAPP and blogs.
2021/1/20-23:
1.finish func eval, buildin_cmd, do_bgfg and waitfg.
2.first push to master.
2021/1/24:
1.finish other funcs.
2.try to debug in my lxc.
3.if alright, push to master.
BAD NEWS:
don't pass test, so I need several days to debug with the help of some blogs.
if pass, I will push to master.
2021/1/24:
debug successfully.

+ 456
- 0
bits.c Ver ficheiro

@ -0,0 +1,456 @@
/*
* CS:APP Data Lab
*
* <Please put your name and userid here>
*
* bits.c - Source file with your solutions to the Lab.
* This is the file you will hand in to your instructor.
*
* WARNING: Do not include the <stdio.h> header; it confuses the dlc
* compiler. You can still use printf for debugging without including
* <stdio.h>, although you might get a compiler warning. In general,
* it's not good practice to ignore compiler warnings, but in this
* case it's OK.
*/
#if 0
/*
* Instructions to Students:
*
* STEP 1: Read the following instructions carefully.
*/
You will provide your solution to the Data Lab by
editing the collection of functions in this source file.
INTEGER CODING RULES:
Replace the "return" statement in each function with one
or more lines of C code that implements the function. Your code
must conform to the following style:
int Funct(arg1, arg2, ...) {
/* brief description of how your implementation works */
int var1 = Expr1;
...
int varM = ExprM;
varJ = ExprJ;
...
varN = ExprN;
return ExprR;
}
Each "Expr" is an expression using ONLY the following:
1. Integer constants 0 through 255 (0xFF), inclusive. You are
not allowed to use big constants such as 0xffffffff.
2. Function arguments and local variables (no global variables).
3. Unary integer operations ! ~
4. Binary integer operations & ^ | + << >>
Some of the problems restrict the set of allowed operators even further.
Each "Expr" may consist of multiple operators. You are not restricted to
one operator per line.
You are expressly forbidden to:
1. Use any control constructs such as if, do, while, for, switch, etc.
2. Define or use any macros.
3. Define any additional functions in this file.
4. Call any functions.
5. Use any other operations, such as &&, ||, -, or ?:
6. Use any form of casting.
7. Use any data type other than int. This implies that you
cannot use arrays, structs, or unions.
You may assume that your machine:
1. Uses 2s complement, 32-bit representations of integers.
2. Performs right shifts arithmetically.
3. Has unpredictable behavior when shifting an integer by more
than the word size.
EXAMPLES OF ACCEPTABLE CODING STYLE:
/*
* pow2plus1 - returns 2^x + 1, where 0 <= x <= 31
*/
int pow2plus1(int x) {
/* exploit ability of shifts to compute powers of 2 */
return (1 << x) + 1;
}
/*
* pow2plus4 - returns 2^x + 4, where 0 <= x <= 31
*/
int pow2plus4(int x) {
/* exploit ability of shifts to compute powers of 2 */
int result = (1 << x);
result += 4;
return result;
}
FLOATING POINT CODING RULES
For the problems that require you to implent floating-point operations,
the coding rules are less strict. You are allowed to use looping and
conditional control. You are allowed to use both ints and unsigneds.
You can use arbitrary integer and unsigned constants.
You are expressly forbidden to:
1. Define or use any macros.
2. Define any additional functions in this file.
3. Call any functions.
4. Use any form of casting.
5. Use any data type other than int or unsigned. This means that you
cannot use arrays, structs, or unions.
6. Use any floating point data types, operations, or constants.
NOTES:
1. Use the dlc (data lab checker) compiler (described in the handout) to
check the legality of your solutions.
2. Each function has a maximum number of operators (! ~ & ^ | + << >>)
that you are allowed to use for your implementation of the function.
The max operator count is checked by dlc. Note that '=' is not
counted; you may use as many of these as you want without penalty.
3. Use the btest test harness to check your functions for correctness.
4. Use the BDD checker to formally verify your functions
5. The maximum number of ops for each function is given in the
header comment for each function. If there are any inconsistencies
between the maximum ops in the writeup and in this file, consider
this file the authoritative source.
/*
* STEP 2: Modify the following functions according the coding rules.
*
* IMPORTANT. TO AVOID GRADING SURPRISES:
* 1. Use the dlc compiler to check that your solutions conform
* to the coding rules.
* 2. Use the BDD checker to formally verify that your solutions produce
* the correct answers.
*/
#endif
/*
* bitAnd - x&y using only ~ and |
* Example: bitAnd(6, 5) = 4
* Legal ops: ~ |
* Max ops: 8
* Rating: 1
*/
int bitAnd(int x, int y) {
int temp1;
int temp2;
int temp3;
int res;
temp1=~x;
temp2=~y;
temp3=temp1|temp2;
res=~temp3;
// use (a AND b) == Not((Not a) or (Not b))
return res;
}
/*
* getByte - Extract byte n from word x
* Bytes numbered from 0 (LSB) to 3 (MSB)
* Examples: getByte(0x12345678,1) = 0x56
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 6
* Rating: 2
*/
int getByte(int x, int n) {
int mask;
int temp;
int res;
mask = (0xff);
temp = x >> (n * 8);
res=mask&temp;
//get the mask 11111111 fit the wanted bit
return res;
}
/*
* logicalShift - shift x to the right by n, using a logical shift
* Can assume that 0 <= n <= 31
* Examples: logicalShift(0x87654321,4) = 0x08765432
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 20
* Rating: 3
*/
int logicalShift(int x, int n) {
int temp1;
int temp2;
int res;
//temp1=(x|-1)<<(32-n);
//temp2=x>>n;
//res=temp1^temp2;
temp1 = ~(1<<31); //n=0,>>-1 wrong! temp1:011111......1 (32)
temp2 = ((temp1 >> n) << 1)+1; //a trick to erase the top n 1s created by the arithmetic shift.
res = temp2 & (x >> n);
return res;
}
/*
* bitCount - returns count of number of 1's in word
* Examples: bitCount(5) = 2, bitCount(7) = 3
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 40
* Rating: 4
*/
int bitCount(int x) {
int count;
int temp1;
int temp2;
int temp3;
int mask1;
int mask2;
int mask3;
int mask4;
int mask5;
temp1 = (0x55) + (0x55 << 8);
temp2 = (0x33) + (0x33 << 8);
temp3 = (0x0f) + (0x0f << 8);
mask1 = (temp1) + (temp1 << 16);
mask2 = (temp2) + (temp2 << 16);
mask3 = (temp3) + (temp3 << 16);
mask4 = (0xff) + (0xff << 16);
mask5 = (0xff) + (0xff << 8);
count = (x & mask1) + ((x >> 1) & mask1);
count = (count & mask2) + ((count >> 2) & mask2);
count = (count & mask3) + ((count >> 4) & mask3);
count = (count & mask4) + ((count >> 8) & mask4);
count = (count & mask5) + ((count >> 16) & mask5);
return count;
}
/*
* bang - Compute !x without using !
* Examples: bang(3) = 0, bang(0) = 1
* Legal ops: ~ & ^ | + << >>
* Max ops: 12
* Rating: 4
*/
int bang(int x) {
int temp1;
int temp2;
int res;
temp1=(~x)+1; //0x00000000 0x80000000 compute (-x)
temp2=(x>>31)&1;
res=1^((((temp1^x)>>31)&1)|temp2);
//???A nice trick???
return res;
}
/*
* tmin - return minimum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmin(void) {
int res;
res=(-1)<<31;
return res;
}
/*
* fitsBits - return 1 if x can be represented as an
* n-bit, two's complement integer.
* 1 <= n <= 32
* Examples: fitsBits(5,3) = 0, fitsBits(-4,3) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 15
* Rating: 2
*/
int fitsBits(int x, int n) {
int temp1;
int temp2;
int res;
temp1=x>>(n-1);
temp2=x>>31;
res=temp1^temp2;
return !res;
}
/*
* divpwr2 - Compute x/(2^n), for 0 <= n <= 30
* Round toward zero
* Examples: divpwr2(15,1) = 7, divpwr2(-33,4) = -2
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 15
* Rating: 2
*/
int divpwr2(int x, int n) {
int temp1=x>>31;
int temp2=(1<<n)+(~0); //2^n-1
x=x+(temp1&temp2);
return x>>n;
}
/*
* negate - return -x
* Example: negate(1) = -1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int negate(int x) {
int res;
res=(~x)+1;;
return res;
}
/*
* isPositive - return 1 if x > 0, return 0 otherwise
* Example: isPositive(-1) = 0.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 8
* Rating: 3
*/
int isPositive(int x) {
int temp1;
int temp2;
int res;
temp1=x>>31;
temp2=temp1&1;
res=(!temp2)&(!!x);
return res;
}
/*
* isLessOrEqual - if x <= y then return 1, else return 0
* Example: isLessOrEqual(4,5) = 1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 24
* Rating: 3
*/
int isLessOrEqual(int x, int y) {
int s1,s2,valid,res;
//first judge two nums are both + or -, if not,easily judge.
//if it does,try x-y or y-x
s1=(x>>31)&1;
s2=(y>>31)&1;
valid=s1^s2; //equal?
res=y+(~x)+1;
return (((!(res>>31))&1)&(!valid))|(valid&(s1)&(!s2));
}
/*
* ilog2 - return floor(log base 2 of x), where x > 0
* Example: ilog2(16) = 4
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 90
* Rating: 4
*/
int ilog2(int x) {
int count;
int temp1;
int temp2;
int temp3;
int temp4;
count=(!!(x>>16))<<4;
temp1=(x>>(count+8));
count=((!!temp1)<<3)+count;
temp2=(x>>(count+4));
count=((!!temp2)<<2)+count;
temp3=(x>>(count+2));
count=((!!temp3)<<1)+count;
temp4=(x>>(count+1));
count=(!!temp4)+count;
return count;
}
/*
* float_neg - Return bit-level equivalent of expression -f for
* floating point argument f.
* Both the argument and result are passed as unsigned int's, but
* they are to be interpreted as the bit-level representations of
* single-precision floating point values.
* When argument is NaN, return argument.
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 10
* Rating: 2
*/
unsigned float_neg(unsigned uf) {
unsigned temp,res;
temp = uf & 0x7fffffff;
res = uf ^ 0x80000000;
if(temp>0x7f800000)
res=uf; //NaN
return res;
}
/*
* float_i2f - Return bit-level equivalent of expression (float) x
* Result is returned as unsigned int, but
* it is to be interpreted as the bit-level representation of a
* single-precision floating point values.
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 30
* Rating: 4
*/
unsigned float_i2f(int x) {
unsigned shiftleft,aftershift,tmp,flag,absx,sign;
shiftleft=0;
absx=x;
sign=0;
if(!x) return 0;
if(x<0){
sign=0x80000000;
absx=(~x)+1;
}
aftershift=absx;
for(;;){
tmp=aftershift;
aftershift=aftershift<<1;
shiftleft++;
if(tmp&0x80000000) break;
}
if((aftershift&0x01ff)>0x0100)
flag=1;
else if((aftershift&0x03ff)==0x0300)
flag=1;
else
flag=0;
return sign+(aftershift>>9)+((159-shiftleft)<<23)+flag;
//according to the design of float value, devide into 3 parts
//aftershift: last part, shiftleft: second part,count the multiples of 2, sign: first part, decide if x is + or -
}
/*
* float_twice - Return bit-level equivalent of expression 2*f for
* floating point argument f.
* Both the argument and result are passed as unsigned int's, but
* they are to be interpreted as the bit-level representation of
* single-precision floating point values.
* When argument is NaN, return argument
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 30
* Rating: 4
*/
unsigned float_twice(unsigned uf) {
unsigned sign,normalized,special,itsign,doutem;
sign=1<<31;
itsign=uf&sign;
normalized=(uf<<1)>>24;
if(normalized==0xff)
special=1;
else
special=0;
//special number: NaN etc.
doutem=uf<<1;
if(special || (!uf) || uf==sign) //0 -0 special
return uf;
else if(normalized) //normalize
return uf + (1<<23);
else
return doutem | itsign; //second and last part are both multipled by 2.
}

+ 333
- 0
mm.c Ver ficheiro

@ -0,0 +1,333 @@
/*
* mm-naive.c - The fastest, least memory-efficient malloc package.
*
* In this naive approach, a block is allocated by simply incrementing
* the brk pointer. A block is pure payload. There are no headers or
* footers. Blocks are never coalesced or reused. Realloc is
* implemented directly using mm_malloc and mm_free.
*
* NOTE TO STUDENTS: Replace this header comment with your own header
* comment that gives a high level description of your solution.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include "mm.h"
#include "memlib.h"
/*********************************************************
* NOTE TO STUDENTS: Before you do anything else, please
* provide your team information in the following struct.
********************************************************/
team_t team = {
/* Team name */
"ateam",
/* First member's full name */
"Harry Bovik",
/* First member's email address */
"bovik@cs.cmu.edu",
/* Second member's full name (leave blank if none) */
"",
/* Second member's email address (leave blank if none) */
""
};
/* single word (4) or double word (8) alignment */
#define ALIGNMENT 8
/* rounds up to the nearest multiple of ALIGNMENT */
#define ALIGN(size) (((size) + (ALIGNMENT-1)) & ~0x7)
#define SIZE_T_SIZE (ALIGN(sizeof(size_t)))
#define WSIZE 4 /* Word and header/footer size (bytes) */
#define DSIZE 8 /* Double word size (bytes) */
#define CHUNKSIZE (1<<12) /* Extend heap by this amount (bytes) */
#define MAX(x, y) ((x) > (y)? (x) : (y))
#define MIN(x, y) ((x) > (y)? (y) : (x))
/* Pack a size and allocated bit into a word(4 bytes) */
#define PACK(size, alloc) ((size) | (alloc))
/* Read and write a word at address p */
#define GET(ptr) (*(unsigned int *)(ptr))
#define PUT(ptr, val) (*(unsigned int *)(ptr) = (val))
/* not affected in the case that the first bit is 1 */
/* if use int, may affected */
/* Read the size and allocated flags from address ptr */
#define GET_SIZE(ptr) (GET(ptr) & ~0x7)
#define GET_ALLOC(ptr) (GET(ptr) & 0x1)
/* ALIGN return the nearest multiple of 8, so the last 3 bits are always 000 */
/* Given block ptr ptr, compute address of its header and footer */
#define HDRP(ptr) ((char *)(ptr) - WSIZE)
#define FTRP(ptr) ((char *)(ptr) + GET_SIZE(HDRP(ptr)) - DSIZE)
/* Given block ptr ptr, compute address of next and previous blocks */
#define NEXT_BLKP(ptr) ((char *)(ptr) + GET_SIZE(((char *)(ptr) - WSIZE)))
#define PREV_BLKP(ptr) ((char *)(ptr) - GET_SIZE(((char *)(ptr) - DSIZE)))
/* ptr means the address of payload */
/*
* I don't know why PREV_BLKP is written like this, but according to the information
* I have found, it seems that this method can work properly.
*/
/* Modified micros */
/* Add two micros only for free blocks */
/* Point to next and prev free block, only free blocks have*/
#define PREV_LINKNODE_RP(ptr) ((char *)(ptr))
#define NEXT_LINKNODE_RP(ptr) ((char *)(ptr) + WSIZE)
char *heap_ptr = NULL;
char *root = NULL;
/*
* Insert_linknode - insert p to the root of explcit list.
*/
inline void insert_linknode(char *p){ //inline decreases the cost of calling the func.
/* insert p to explcit list. */
char *next = GET(root);
if (next != NULL)
PUT(PREV_LINKNODE_RP(next), p);
PUT(NEXT_LINKNODE_RP(p), next);
PUT(root, p);
}
/*
* Del_linknode - delete linknode p.
*/
inline void del_linknode(char *p){
char *prev = GET(PREV_LINKNODE_RP(p));
char *next = GET(NEXT_LINKNODE_RP(p));
if (prev == NULL){
if (next != NULL)
PUT(PREV_LINKNODE_RP(next), 0);
PUT(root, next);
}
else if (prev != NULL){
if (next != NULL)
PUT(PREV_LINKNODE_RP(next), prev);
PUT(NEXT_LINKNODE_RP(prev), next);
}
PUT(NEXT_LINKNODE_RP(p), 0);
PUT(PREV_LINKNODE_RP(p), 0);
}
/*
* coalesce - Boundary tag coalescing. Return ptr to coalesced block
*/
static void *coalesce(void *ptr)
{
size_t prev_alloc = GET_ALLOC(FTRP(PREV_BLKP(ptr)));
size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(ptr)));
size_t size = GET_SIZE(HDRP(ptr));
if (prev_alloc && next_alloc) { /* left and right used */
//return ptr;
}
else if (prev_alloc && !next_alloc) { /* only right free */
size += GET_SIZE(HDRP(NEXT_BLKP(ptr)));
del_linknode(NEXT_LINKNODE_RP(ptr)); /* remove from linklist*/
PUT(HDRP(ptr), PACK(size, 0));
PUT(FTRP(ptr), PACK(size,0));
}
else if (!prev_alloc && next_alloc) { /* only left free */
size += GET_SIZE(HDRP(PREV_BLKP(ptr)));
del_linknode(PREV_BLKP(ptr));
PUT(FTRP(ptr), PACK(size, 0));
PUT(HDRP(PREV_BLKP(ptr)), PACK(size, 0));
ptr = PREV_BLKP(ptr);
}
else { /* both sides free */
size += GET_SIZE(HDRP(PREV_BLKP(ptr))) +
GET_SIZE(FTRP(NEXT_BLKP(ptr)));
del_linknode(PREV_BLKP(ptr));
del_linknode(NEXT_BLKP(ptr));
PUT(HDRP(PREV_BLKP(ptr)), PACK(size, 0));
PUT(FTRP(NEXT_BLKP(ptr)), PACK(size, 0));
ptr = PREV_BLKP(ptr);
}
insert_linknode(ptr);
return ptr;
}
/*
* extend_heap - Extend heap with free block and return its block pointer
*/
static void *extend_heap(size_t extendsize)
{
char *ptr;
size_t size;
/* Allocate an even number of extendsize to maintain alignment */
size = (extendsize % 2) ? (extendsize+1) * WSIZE : extendsize * WSIZE;
if ((long)(ptr = mem_sbrk(size)) == -1) /* this means ptr -> 0xffffffff */
return NULL;
/* Initialize free block header,footer and the epilogue header */
PUT(HDRP(ptr), PACK(size, 0)); /* Free block header */
PUT(FTRP(ptr), PACK(size, 0)); /* Free block footer */
// HDRP make a left 8-bits shift, the same to a node size.
PUT(NEXT_LINKNODE_RP(ptr), 0); /* Next linknode */
PUT(PREV_LINKNODE_RP(ptr), 0); /* Prev linknode */
PUT(HDRP(NEXT_BLKP(ptr)), PACK(0, 1)); /* New epilogue header */
/* Coalesce free blocks */
return coalesce(ptr);
}
/*
* find_fit - Find a fit for a block with size bytes
*/
static void *find_fit(size_t asize)
{
char *tmp = GET(root);
int count = 0;
while (tmp != NULL){
if (GET_SIZE(HDRP(tmp)) >= asize && (count++) != 0)
return tmp;
tmp = GET(NEXT_LINKNODE_RP(tmp));
}
return NULL; /* No fit */
}
/*
* place - Place block of size bytes at start of free block ptr
* and split if remainder would be at least minimum block size
*/
static void place(void *ptr, size_t size)
{
size_t newsize = GET_SIZE(HDRP(ptr));
del_linknode(ptr);
if ((newsize - size) >= (2*DSIZE)) {
PUT(HDRP(ptr), PACK(size, 1));
PUT(FTRP(ptr), PACK(size, 1));
ptr = NEXT_BLKP(ptr);
PUT(HDRP(ptr), PACK(newsize-size, 0));
PUT(FTRP(ptr), PACK(newsize-size, 0));
PUT(NEXT_LINKNODE_RP(ptr), 0);
PUT(PREV_LINKNODE_RP(ptr), 0);
coalesce(ptr);
}
else {
PUT(HDRP(ptr), PACK(newsize, 1));
PUT(FTRP(ptr), PACK(newsize, 1));
}
}
int mm_init(void)
{
/* Create the initial empty heap */
if ((heap_ptr = mem_sbrk(6*WSIZE)) == (void *)-1) /* 0xffffffff */
return -1;
PUT(heap_ptr, 0); /* Alignment padding */
PUT(heap_ptr + (1*WSIZE), 0); /* Free prev linknode */
PUT(heap_ptr + (2*WSIZE), 0); /* Free next linknode */
PUT(heap_ptr + (3*WSIZE), PACK(DSIZE, 1)); /* Prologue header */
PUT(heap_ptr + (4*WSIZE), PACK(DSIZE, 1)); /* Prologue footer */
PUT(heap_ptr + (5*WSIZE), PACK(0, 1)); /* Epilogue header */
root = heap_ptr + (1 * WSIZE);
heap_ptr += (4*WSIZE);
/* Extend the empty heap with a free block of CHUNKSIZE bytes */
if (extend_heap(CHUNKSIZE/WSIZE) == NULL)
return -1;
return 0;
}
void *mm_malloc(size_t size)
{
size_t newsize; /* Adjusted block size */
size_t extendsize; /* Amount to extend heap if no fit */
char *ptr;
if (heap_ptr == NULL){
mm_init();
}
if (size == 0)
return NULL;
/* Adjust block size to include overhead and alignment reqs. */
/* Need to use this method, but I don't know why */
if (size <= DSIZE)
newsize = 2*DSIZE;
else
newsize = DSIZE * ((size + (DSIZE) + (DSIZE-1)) / DSIZE);
/* Search the free list for a fit */
if ((ptr = find_fit(newsize)) != NULL) {
place(ptr, newsize);
return ptr;
}
/* No fit found. Get more memory and place the block */
extendsize = MAX(newsize,CHUNKSIZE);
if ((ptr = extend_heap(extendsize/WSIZE)) == NULL)
return NULL;
place(ptr, newsize);
return ptr;
}
void mm_free(void *ptr)
{
if (ptr == NULL)
return;
size_t size = GET_SIZE(HDRP(ptr));
PUT(HDRP(ptr), PACK(size, 0));
PUT(FTRP(ptr), PACK(size, 0));
/* Reset linknodes */
PUT(NEXT_LINKNODE_RP(ptr), 0);
PUT(PREV_LINKNODE_RP(ptr), 0);
coalesce(ptr);
}
void *mm_realloc(void *ptr, size_t size)
{
size_t oldsize;
void *newptr;
if(size == 0) {
mm_free(ptr);
return 0;
}
if(ptr == NULL) {
return mm_malloc(size);
}
newptr = mm_malloc(size);
/* realloc failed */
if(newptr == NULL) {
return 0;
}
/* Copy the old heap area. */
oldsize = GET_SIZE(HDRP(ptr));
if(size < oldsize)
oldsize = size;
memcpy(newptr, ptr, oldsize);
/* Free the old block. */
mm_free(ptr);
return newptr;
}

+ 659
- 0
tsh.c Ver ficheiro

@ -0,0 +1,659 @@
/*
* tsh - A tiny shell program with job control
*
* <Put your name and login ID here>
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
/* Misc manifest constants */
#define MAXLINE 1024 /* max line size */
#define MAXARGS 128 /* max args on a command line */
#define MAXJOBS 16 /* max jobs at any point in time */
#define MAXJID 1<<16 /* max job ID */
/* Job states */
#define UNDEF 0 /* undefined */
#define FG 1 /* running in foreground */
#define BG 2 /* running in background */
#define ST 3 /* stopped */
/*
* Jobs states: FG (foreground), BG (background), ST (stopped)
* Job state transitions and enabling actions:
* FG -> ST : ctrl-z
* ST -> FG : fg command
* ST -> BG : bg command
* BG -> FG : fg command
* At most 1 job can be in the FG state.
*/
/* Global variables */
extern char **environ; /* defined in libc */
char prompt[] = "tsh> "; /* command line prompt (DO NOT CHANGE) */
int verbose = 0; /* if true, print additional output */
int nextjid = 1; /* next job ID to allocate */
char sbuf[MAXLINE]; /* for composing sprintf messages */
struct job_t { /* The job struct */
pid_t pid; /* job PID */
int jid; /* job ID [1, 2, ...] */
int state; /* UNDEF, BG, FG, or ST */
char cmdline[MAXLINE]; /* command line */
};
struct job_t jobs[MAXJOBS]; /* The job list */
/* End global variables */
/* Function prototypes */
/* Here are the functions that you will implement */
void eval(char *cmdline);
int builtin_cmd(char **argv);
void do_bgfg(char **argv);
void waitfg(pid_t pid);
void sigchld_handler(int sig);
void sigtstp_handler(int sig);
void sigint_handler(int sig);
/* Here are helper routines that we've provided for you */
int parseline(const char *cmdline, char **argv);
void sigquit_handler(int sig);
void clearjob(struct job_t *job);
void initjobs(struct job_t *jobs);
int maxjid(struct job_t *jobs);
int addjob(struct job_t *jobs, pid_t pid, int state, char *cmdline);
int deletejob(struct job_t *jobs, pid_t pid);
pid_t fgpid(struct job_t *jobs);
struct job_t *getjobpid(struct job_t *jobs, pid_t pid);
struct job_t *getjobjid(struct job_t *jobs, int jid);
int pid2jid(pid_t pid);
void listjobs(struct job_t *jobs);
void usage(void);
void unix_error(char *msg);
void app_error(char *msg);
typedef void handler_t(int);
handler_t *Signal(int signum, handler_t *handler);
/*
* main - The shell's main routine
*/
int main(int argc, char **argv)
{
char c;
char cmdline[MAXLINE];
int emit_prompt = 1; /* emit prompt (default) */
/* Redirect stderr to stdout (so that driver will get all output
* on the pipe connected to stdout) */
dup2(1, 2);
/* Parse the command line */
while ((c = getopt(argc, argv, "hvp")) != EOF) {
switch (c) {
case 'h': /* print help message */
usage();
break;
case 'v': /* emit additional diagnostic info */
verbose = 1;
break;
case 'p': /* don't print a prompt */
emit_prompt = 0; /* handy for automatic testing */
break;
default:
usage();
}
}
/* Install the signal handlers */
/* These are the ones you will need to implement */
Signal(SIGINT, sigint_handler); /* ctrl-c */
Signal(SIGTSTP, sigtstp_handler); /* ctrl-z */
Signal(SIGCHLD, sigchld_handler); /* Terminated or stopped child */
/* This one provides a clean way to kill the shell */
Signal(SIGQUIT, sigquit_handler);
/* Initialize the job list */
initjobs(jobs);
/* Execute the shell's read/eval loop */
while (1) {
/* Read command line */
if (emit_prompt) {
printf("%s", prompt);
fflush(stdout);
}
if ((fgets(cmdline, MAXLINE, stdin) == NULL) && ferror(stdin))
app_error("fgets error");
if (feof(stdin)) { /* End of file (ctrl-d) */
fflush(stdout);
exit(0);
}
/* Evaluate the command line */
eval(cmdline);
fflush(stdout);
fflush(stdout);
}
exit(0); /* control never reaches here */
}
/*
* eval - Evaluate the command line that the user has just typed in
*
* If the user has requested a built-in command (quit, jobs, bg or fg)
* then execute it immediately. Otherwise, fork a child process and
* run the job in the context of the child. If the job is running in
* the foreground, wait for it to terminate and then return. Note:
* each child process must have a unique process group ID so that our
* background children don't receive SIGINT (SIGTSTP) from the kernel
* when we type ctrl-c (ctrl-z) at the keyboard.
*/
void eval(char *cmdline)
{
/* Init */
int bg;
char buf[MAXLINE];
char *argv[MAXARGS];
pid_t pid;
sigset_t mask;
/* build argv first */
strcpy(buf, cmdline);
bg = parseline(buf, argv);
if(!argv[0]) /* not found PATH */
return;
if(!builtin_cmd(argv)) {
/* if builtin, exec and exit */
sigemptyset(&mask); /* clear the set */
sigaddset(&mask, SIGCHLD); /* add stop to mask first */
sigprocmask(SIG_BLOCK, &mask, NULL); /* inorder to block the parent */
if((pid = fork()) < 0) {
unix_error("forking error");
}
else if(pid == 0){
sigprocmask(SIG_UNBLOCK, &mask, NULL); /* set unblock */
setpgid(0, 0); /* set group pid to 0 */
/* if command not found, exit */
if(execvp(argv[0], argv) < 0) {
printf("%s: Command not found.\n", argv[0]);
exit(1);
}
}
/* command found */
int state = bg ? BG : FG; /* background? foreground? */
addjob(jobs, pid, state, cmdline); /* exec cmd ok -> job ready to go */
sigprocmask(SIG_UNBLOCK, &mask, NULL); /* set unblock before exec */
/*
* From the Internet: 线线线
* 线线线
* .exe 线线
*/
if(!bg) /* foreground need to wait other fg */
waitfg(pid);
else /* background can exec */
printf("[%d] (%d) %s", pid2jid(pid), pid, cmdline);
}
}
/*
* parseline - Parse the command line and build the argv array.
*
* Characters enclosed in single quotes are treated as a single
* argument. Return true if the user has requested a BG job, false if
* the user has requested a FG job.
*/
int parseline(const char *cmdline, char **argv)
{
static char array[MAXLINE]; /* holds local copy of command line */
char *buf = array; /* ptr that traverses command line */
char *delim; /* points to first space delimiter */
int argc; /* number of args */
int bg; /* background job? */
strcpy(buf, cmdline);
buf[strlen(buf)-1] = ' '; /* replace trailing '\n' with space */
while (*buf && (*buf == ' ')) /* ignore leading spaces */
buf++;
/* Build the argv list */
argc = 0;
if (*buf == '\'') {
buf++;
delim = strchr(buf, '\'');
}
else {
delim = strchr(buf, ' ');
}
while (delim) {
argv[argc++] = buf;
*delim = '\0';
buf = delim + 1;
while (*buf && (*buf == ' ')) /* ignore spaces */
buf++;
if (*buf == '\'') {
buf++;
delim = strchr(buf, '\'');
}
else {
delim = strchr(buf, ' ');
}
}
argv[argc] = NULL;
if (argc == 0) /* ignore blank line */
return 1;
/* should the job run in the background? */
if ((bg = (*argv[argc-1] == '&')) != 0) {
argv[--argc] = NULL;
}
return bg;
}
/*
* builtin_cmd - If the user has typed a built-in command then execute
* it immediately.
*/
int builtin_cmd(char **argv)
{
/* 1 - a cmd that can be exec, 0 - not */
if(!argv[0]) { /* void cmd */
return 1;
}
else if(!strcmp(argv[0], "&")) {
return 1;
}
else if(!strcmp(argv[0], "jobs")) { /* cmd to list jobs */
listjobs(jobs);
return 1;
}
else if(!strcmp(argv[0], "quit")) { /* cmd to quit, nothing to exec, so return 0 */
exit(0);
}
else if((!strcmp(argv[0], "bg")) || (!strcmp(argv[0], "fg"))) { /* cmd to exec fg/bg */
do_bgfg(argv);
return 1;
}
else{
return 0; /* not a builtin command */
}
}
/*
* do_bgfg - Execute the builtin bg and fg commands
*/
void do_bgfg(char **argv)
{
/* init */
pid_t pid;
int jid;
struct job_t *job;
if(!argv[1]) { /* have no PID/JID arguments */
printf("%s command requires PID or %%jobid argument\n", argv[0]);
return;
}
if(*argv[1] == '%') { /* %: need jid */
jid = atoi(argv[1] + 1); /* get jid */
if( (job = getjobjid(jobs, jid)) == 0 ) { /* illegal jid */
printf("%s: No such job\n", argv[1]);
return;
}
pid = job->pid; /* get job and pid */
}
else if(isdigit(*argv[1])) { /* if get a pid */
pid = atoi(argv[1]); /* use pid(not %) */
if( (job = getjobjid(jobs, jid)) == 0 ) { /* illegal pid */
printf("(%d): No such process\n", pid);
return;
}
}
else {
printf("%s: argument must be a PID or %%jobid\n", argv[0]);
return;
}
if(!job) { /* illegal job */
printf("Error -- no such job.\n");
return;
}
if(!strcmp(argv[0], "bg")) { /* if background */
kill(-pid, SIGCONT); /* SIGCONT -- continue to exec */
job->state = BG; /* state to BG(background) */
printf("[%d] (%d) %s", job->jid, pid, job->cmdline);
}
else { /* if foreground */
kill(-pid, SIGCONT); /* SIGCONT -- continue to exec */
job->state = FG; /* state to FG(foreground) */
waitfg(pid); /* need to wait other FGs */
}
}
/*
* waitfg - Block until process pid is no longer the foreground process
*/
void waitfg(pid_t pid)
{
if(pid == 0)
return;
/*
* From the Internet:Thread.Sleep(0) 线0Thread.Sleep(0)线线
* Thread.Sleep(0) 线cpu线使
*/
while(pid == fgpid(jobs))
sleep(0);
return;
}
/*****************
* Signal handlers
*****************/
/*
* sigchld_handler - The kernel sends a SIGCHLD to the shell whenever
* a child job terminates (becomes a zombie), or stops because it
* received a SIGSTOP or SIGTSTP signal. The handler reaps all
* available zombie children, but doesn't wait for any other
* currently running children to terminate.
*/
void sigchld_handler(int sig)
{
pid_t pid;
int status;
while ((pid = waitpid(fgpid(jobs), &status, WNOHANG|WUNTRACED)) > 0) {
/* WNOHANG 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若结束,则返回该子进程的ID。*/
/* WUNTRACED 若子进程进入暂停状态,则马上返回,但子进程的结束状态不予以理会。WIFSTOPPED(status)宏确定返回值是否对应与一个暂停子进程。*/
if (WIFSTOPPED(status)){ /* if stopped */
getjobpid(jobs, pid)->state = ST; /* change state to ST(stopped) */
int jid = pid2jid(pid);
printf("Job [%d] (%d) Stopped by signal %d\n", jid, pid, WSTOPSIG(status));
}
else if (WIFSIGNALED(status)){ /* if signaled */
int jid = pid2jid(pid); /* delete */
printf("Job [%d] (%d) terminated by signal %d\n", jid, pid, WTERMSIG(status));
deletejob(jobs, pid);
}
else if (WIFEXITED(status)){ /* if exited */
deletejob(jobs, pid);
}
else;
}
return;
}
/*
* sigint_handler - The kernel sends a SIGINT to the shell whenver the
* user types ctrl-c at the keyboard. Catch it and send it along
* to the foreground job.
*/
void sigint_handler(int sig)
{
pid_t pid;
if( (pid = fgpid(jobs)) <= 0)
return; /* illegal pid */
kill(-pid, sig);
return;
}
/*
* sigtstp_handler - The kernel sends a SIGTSTP to the shell whenever
* the user types ctrl-z at the keyboard. Catch it and suspend the
* foreground job by sending it a SIGTSTP.
*/
void sigtstp_handler(int sig)
{
pid_t pid;
if ((pid = fgpid(jobs)) <= 0)
return; /* illegal pid */
kill(-pid, sig);
return;
}
/*********************
* End signal handlers
*********************/
/***********************************************
* Helper routines that manipulate the job list
**********************************************/
/* clearjob - Clear the entries in a job struct */
void clearjob(struct job_t *job) {
job->pid = 0;
job->jid = 0;
job->state = UNDEF;
job->cmdline[0] = '\0';
}
/* initjobs - Initialize the job list */
void initjobs(struct job_t *jobs) {
int i;
for (i = 0; i < MAXJOBS; i++)
clearjob(&jobs[i]);
}
/* maxjid - Returns largest allocated job ID */
int maxjid(struct job_t *jobs)
{
int i, max=0;
for (i = 0; i < MAXJOBS; i++)
if (jobs[i].jid > max)
max = jobs[i].jid;
return max;
}
/* addjob - Add a job to the job list */
int addjob(struct job_t *jobs, pid_t pid, int state, char *cmdline)
{
int i;
if (pid < 1)
return 0;
for (i = 0; i < MAXJOBS; i++) {
if (jobs[i].pid == 0) {
jobs[i].pid = pid;
jobs[i].state = state;
jobs[i].jid = nextjid++;
if (nextjid > MAXJOBS)
nextjid = 1;
strcpy(jobs[i].cmdline, cmdline);
if(verbose){
printf("Added job [%d] %d %s\n", jobs[i].jid, jobs[i].pid, jobs[i].cmdline);
}
return 1;
}
}
printf("Tried to create too many jobs\n");
return 0;
}
/* deletejob - Delete a job whose PID=pid from the job list */
int deletejob(struct job_t *jobs, pid_t pid)
{
int i;
if (pid < 1)
return 0;
for (i = 0; i < MAXJOBS; i++) {
if (jobs[i].pid == pid) {
clearjob(&jobs[i]);
nextjid = maxjid(jobs)+1;
return 1;
}
}
return 0;
}
/* fgpid - Return PID of current foreground job, 0 if no such job */
pid_t fgpid(struct job_t *jobs) {
int i;
for (i = 0; i < MAXJOBS; i++)
if (jobs[i].state == FG)
return jobs[i].pid;
return 0;
}
/* getjobpid - Find a job (by PID) on the job list */
struct job_t *getjobpid(struct job_t *jobs, pid_t pid) {
int i;
if (pid < 1)
return NULL;
for (i = 0; i < MAXJOBS; i++)
if (jobs[i].pid == pid)
return &jobs[i];
return NULL;
}
/* getjobjid - Find a job (by JID) on the job list */
struct job_t *getjobjid(struct job_t *jobs, int jid)
{
int i;
if (jid < 1)
return NULL;
for (i = 0; i < MAXJOBS; i++)
if (jobs[i].jid == jid)
return &jobs[i];
return NULL;
}
/* pid2jid - Map process ID to job ID */
int pid2jid(pid_t pid)
{
int i;
if (pid < 1)
return 0;
for (i = 0; i < MAXJOBS; i++)
if (jobs[i].pid == pid) {
return jobs[i].jid;
}
return 0;
}
/* listjobs - Print the job list */
void listjobs(struct job_t *jobs)
{
int i;
for (i = 0; i < MAXJOBS; i++) {
if (jobs[i].pid != 0) {
printf("[%d] (%d) ", jobs[i].jid, jobs[i].pid);
switch (jobs[i].state) {
case BG:
printf("Running ");
break;
case FG:
printf("Foreground ");
break;
case ST:
printf("Stopped ");
break;
default:
printf("listjobs: Internal error: job[%d].state=%d ",
i, jobs[i].state);
}
printf("%s", jobs[i].cmdline);
}
}
}
/******************************
* end job list helper routines
******************************/
/***********************
* Other helper routines
***********************/
/*
* usage - print a help message
*/
void usage(void)
{
printf("Usage: shell [-hvp]\n");
printf(" -h print this message\n");
printf(" -v print additional diagnostic information\n");
printf(" -p do not emit a command prompt\n");
exit(1);
}
/*
* unix_error - unix-style error routine
*/
void unix_error(char *msg)
{
fprintf(stdout, "%s: %s\n", msg, strerror(errno));
exit(1);
}
/*
* app_error - application-style error routine
*/
void app_error(char *msg)
{
fprintf(stdout, "%s\n", msg);
exit(1);
}
/*
* Signal - wrapper for the sigaction function
*/
handler_t *Signal(int signum, handler_t *handler)
{
struct sigaction action, old_action;
action.sa_handler = handler;
sigemptyset(&action.sa_mask); /* block sigs of type being handled */
action.sa_flags = SA_RESTART; /* restart syscalls if possible */
if (sigaction(signum, &action, &old_action) < 0)
unix_error("Signal error");
return (old_action.sa_handler);
}
/*
* sigquit_handler - The driver program can gracefully terminate the
* child shell by sending it a SIGQUIT signal.
*/
void sigquit_handler(int sig)
{
printf("Terminating after receipt of SIGQUIT signal\n");
exit(1);
}

Carregando…
Cancelar
Guardar