@ -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. |
@ -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. | |||||
} |
@ -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; | |||||
} |
@ -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) 并非是真的要线程挂起0毫秒,意义在于这次调用Thread.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); | |||||
} |