Fixes race-bug in overflow/bit event handling
[akaros.git] / user / c3po / stack / stack.c
1 #include "stacklink.h"
2 #include "util.h"
3
4 #ifndef DEBUG_stack_c
5 #undef debug
6 #define debug(...)
7 #undef tdebug
8 #define tdebug(...)
9 #endif
10
11 #define MAX_BUCKETS 32
12
13 int stack_fingerprint = 0;
14
15 int stack_extern = 0;
16 int stack_check_link = 0;
17 int stack_check_nolink = 0;
18 int stack_nocheck = 0;
19
20 int stack_waste_ext = 0;
21 int stack_waste_int = 0;
22 int stack_allocchunks[MAX_BUCKETS] =
23 {
24   0, 0, 0, 0, 0, 0, 0, 0,
25   0, 0, 0, 0, 0, 0, 0, 0,
26   0, 0, 0, 0, 0, 0, 0, 0,
27   0, 0, 0, 0, 0, 0, 0, 0,
28 };
29
30 // disable stack checking for initial thread
31 void *stack_bottom = NULL;
32 void *stack_freechunks[MAX_BUCKETS] =
33 {
34   0, 0, 0, 0, 0, 0, 0, 0,
35   0, 0, 0, 0, 0, 0, 0, 0,
36   0, 0, 0, 0, 0, 0, 0, 0,
37   0, 0, 0, 0, 0, 0, 0, 0,
38 };
39
40 void stack_alloc_many_chunks(int bucket)
41 {
42   int bytes = 1 << 16; // 64 KB
43   char *p = (char*) malloc(bytes);
44
45   if (p != NULL) {
46     int chunkbytes = 1 << (bucket + 10);
47     char *base = p;
48
49     // get pointer to end of memory area and align
50     p += bytes;
51     p = (char*) (((int) p) & ~(chunkbytes - 1));
52
53     // we should get at least one chunk
54     assert((p - base) >= chunkbytes);
55
56     while ((p - base) >= chunkbytes) {
57       *(((void**) p) - 1) = stack_freechunks[bucket];
58       stack_freechunks[bucket] = p;
59
60       debug("allocated %p\n", p);
61
62       p -= chunkbytes;
63     }
64   } else {
65     output("malloc error\n");
66     abort();
67   }
68 }
69
70 void stack_alloc_one_chunk(int bucket)
71 {
72   int bytes = 1 << (bucket + 10);
73   char *p = (char*) malloc(bytes);
74
75   if (p != NULL) {
76     p += bytes;
77
78     *(((void**) p) - 1) = stack_freechunks[bucket];
79     stack_freechunks[bucket] = p;
80
81     debug("allocated %p\n", p);
82   } else {
83     output("malloc error\n");
84     abort();
85   }
86 }
87
88 void stack_alloc_chunk(int bucket)
89 {
90   assert(bucket >= 0);
91   if (bucket < 5) {
92     stack_alloc_many_chunks(bucket);
93   } else {
94     stack_alloc_one_chunk(bucket);
95   }
96 }
97
98 void *stack_get_chunk(int bucket)
99 {
100   void *chunk;
101   GET_CHUNK(bucket, chunk);
102   return chunk;
103 }
104
105 void stack_return_chunk(int bucket, void *chunk)
106 {
107   // FIXME: this needs to follow any chained pages that still remain, in the case of pthread_exit()
108
109   RETURN_CHUNK(bucket, chunk);
110 }
111
112 void stack_report_call_stats(void)
113 {
114   output("links:      %d check/links    %d check/nolinks\n"
115          "            %d externals    %d nochecks\n",
116          stack_check_link, stack_check_nolink,
117          stack_extern, stack_nocheck);
118 }
119
120 void stack_report_usage_stats(void)
121 {
122   int total = 0;
123   int size;
124   int i;
125
126   for (i = 0, size = 1; i < MAX_BUCKETS; i++, size <<= 1) {
127     total += (stack_allocchunks[i] * size);
128   }
129
130   output("stack:      %d KB allocated    %d KB internal waste\n",
131          total, stack_waste_int / 1024);
132 }
133
134 void stack_report_link(void *chunk, int used, int node, int succ)
135 {
136   output("linking stack %p (used %d node %d succ %d )\n",
137          chunk, used, node, succ);
138 }
139
140 void stack_report_unlink(void *chunk)
141 {
142   output("unlinking stack %p\n", chunk);
143 }
144
145 void stack_report_overflow(void)
146 {
147   abort();
148 }
149
150 void stack_report_unreachable(int id, char *name)
151 {
152   output("error: reached unreachable node (%d, %s)\n", id, name);
153   abort();
154 }