| 35 | } |
| 36 | |
| 37 | void free(void *block) |
| 38 | { |
| 39 | header_t *header, *tmp; |
| 40 | /* program break is the end of the process's data segment */ |
| 41 | void *programbreak; |
| 42 | |
| 43 | if (!block) |
| 44 | return; |
| 45 | pthread_mutex_lock(&global_malloc_lock); |
| 46 | header = (header_t*)block - 1; |
| 47 | /* sbrk(0) gives the current program break address */ |
| 48 | programbreak = sbrk(0); |
| 49 | |
| 50 | /* |
| 51 | Check if the block to be freed is the last one in the |
| 52 | linked list. If it is, then we could shrink the size of the |
| 53 | heap and release memory to OS. Else, we will keep the block |
| 54 | but mark it as free. |
| 55 | */ |
| 56 | if ((char*)block + header->s.size == programbreak) { |
| 57 | if (head == tail) { |
| 58 | head = tail = NULL; |
| 59 | } else { |
| 60 | tmp = head; |
| 61 | while (tmp) { |
| 62 | if(tmp->s.next == tail) { |
| 63 | tmp->s.next = NULL; |
| 64 | tail = tmp; |
| 65 | } |
| 66 | tmp = tmp->s.next; |
| 67 | } |
| 68 | } |
| 69 | /* |
| 70 | sbrk() with a negative argument decrements the program break. |
| 71 | So memory is released by the program to OS. |
| 72 | */ |
| 73 | sbrk(0 - header->s.size - sizeof(header_t)); |
| 74 | /* Note: This lock does not really assure thread |
| 75 | safety, because sbrk() itself is not really |
| 76 | thread safe. Suppose there occurs a foregin sbrk(N) |
| 77 | after we find the program break and before we decrement |
| 78 | it, then we end up realeasing the memory obtained by |
| 79 | the foreign sbrk(). |
| 80 | */ |
| 81 | pthread_mutex_unlock(&global_malloc_lock); |
| 82 | return; |
| 83 | } |
| 84 | header->s.is_free = 1; |
| 85 | pthread_mutex_unlock(&global_malloc_lock); |
| 86 | } |
| 87 | |
| 88 | void *mymalloc(size_t size) |
| 89 | { |
searching dependent graphs…