[10255] | 1 | #define MODULE_LOG_PREFIX "gc"
|
---|
| 2 |
|
---|
[4296] | 3 | #include "globals.h"
|
---|
[7570] | 4 | #include "oscam-garbage.h"
|
---|
[7583] | 5 | #include "oscam-lock.h"
|
---|
[7585] | 6 | #include "oscam-string.h"
|
---|
[7644] | 7 | #include "oscam-time.h"
|
---|
[7570] | 8 |
|
---|
[10814] | 9 | #define HASH_BUCKETS 250
|
---|
[4296] | 10 |
|
---|
[8951] | 11 | struct cs_garbage
|
---|
| 12 | {
|
---|
[8960] | 13 | time_t time;
|
---|
| 14 | void *data;
|
---|
[8951] | 15 | #ifdef WITH_DEBUG
|
---|
[8960] | 16 | char *file;
|
---|
[10814] | 17 | uint32_t line;
|
---|
[8951] | 18 | #endif
|
---|
[8960] | 19 | struct cs_garbage *next;
|
---|
[4296] | 20 | };
|
---|
| 21 |
|
---|
[10814] | 22 | static int32_t counter = 0;
|
---|
| 23 | static pthread_mutex_t add_lock;
|
---|
[8447] | 24 | static struct cs_garbage *garbage_first[HASH_BUCKETS];
|
---|
| 25 | static CS_MUTEX_LOCK garbage_lock[HASH_BUCKETS];
|
---|
| 26 | static pthread_t garbage_thread;
|
---|
| 27 | static int32_t garbage_collector_active;
|
---|
| 28 | static int32_t garbage_debug;
|
---|
[4442] | 29 |
|
---|
[4965] | 30 | #ifdef WITH_DEBUG
|
---|
[10826] | 31 | void add_garbage_debug(void *data, char *file, uint32_t line)
|
---|
[8951] | 32 | {
|
---|
[4965] | 33 | #else
|
---|
[8951] | 34 | void add_garbage(void *data)
|
---|
| 35 | {
|
---|
[4965] | 36 | #endif
|
---|
[8960] | 37 | if(!data)
|
---|
| 38 | { return; }
|
---|
[7158] | 39 |
|
---|
[8960] | 40 | if(!garbage_collector_active || garbage_debug == 1)
|
---|
| 41 | {
|
---|
[9277] | 42 | NULLFREE(data);
|
---|
[8960] | 43 | return;
|
---|
| 44 | }
|
---|
[7158] | 45 |
|
---|
[10817] | 46 | SAFE_MUTEX_LOCK(&add_lock);
|
---|
[10814] | 47 |
|
---|
| 48 | int32_t bucket = counter++;
|
---|
| 49 |
|
---|
| 50 | if(counter >= HASH_BUCKETS)
|
---|
[8960] | 51 | {
|
---|
[10814] | 52 | counter = 0;
|
---|
| 53 | }
|
---|
| 54 |
|
---|
[10817] | 55 | SAFE_MUTEX_UNLOCK(&add_lock);
|
---|
[10814] | 56 |
|
---|
| 57 | struct cs_garbage *garbage = (struct cs_garbage*)malloc(sizeof(struct cs_garbage));
|
---|
| 58 | if(garbage == NULL)
|
---|
| 59 | {
|
---|
[9277] | 60 | cs_log("*** MEMORY FULL -> FREEING DIRECT MAY LEAD TO INSTABILITY!!!! ***");
|
---|
| 61 | NULLFREE(data);
|
---|
[8960] | 62 | return;
|
---|
| 63 | }
|
---|
| 64 | garbage->time = time(NULL);
|
---|
| 65 | garbage->data = data;
|
---|
[10814] | 66 | garbage->next = NULL;
|
---|
[8014] | 67 | #ifdef WITH_DEBUG
|
---|
[8960] | 68 | garbage->file = file;
|
---|
| 69 | garbage->line = line;
|
---|
[8014] | 70 | #endif
|
---|
[10814] | 71 |
|
---|
[10817] | 72 | cs_writelock(__func__, &garbage_lock[bucket]);
|
---|
[7158] | 73 |
|
---|
[6429] | 74 | #ifdef WITH_DEBUG
|
---|
[8960] | 75 | if(garbage_debug == 2)
|
---|
| 76 | {
|
---|
| 77 | struct cs_garbage *garbagecheck = garbage_first[bucket];
|
---|
| 78 | while(garbagecheck)
|
---|
| 79 | {
|
---|
| 80 | if(garbagecheck->data == data)
|
---|
| 81 | {
|
---|
| 82 | cs_log("Found a try to add garbage twice. Not adding the element to garbage list...");
|
---|
| 83 | cs_log("Current garbage addition: %s, line %d.", file, line);
|
---|
| 84 | cs_log("Original garbage addition: %s, line %d.", garbagecheck->file, garbagecheck->line);
|
---|
[10817] | 85 | cs_writeunlock(__func__, &garbage_lock[bucket]);
|
---|
[9277] | 86 | NULLFREE(garbage);
|
---|
[8960] | 87 | return;
|
---|
| 88 | }
|
---|
| 89 | garbagecheck = garbagecheck->next;
|
---|
| 90 | }
|
---|
| 91 | }
|
---|
[6429] | 92 | #endif
|
---|
[7158] | 93 |
|
---|
[10814] | 94 | garbage->next = garbage_first[bucket];
|
---|
| 95 | garbage_first[bucket] = garbage;
|
---|
| 96 |
|
---|
[10817] | 97 | cs_writeunlock(__func__, &garbage_lock[bucket]);
|
---|
[4296] | 98 | }
|
---|
| 99 |
|
---|
[8498] | 100 | static pthread_cond_t sleep_cond;
|
---|
[8592] | 101 | static pthread_mutex_t sleep_cond_mutex;
|
---|
[8498] | 102 |
|
---|
[8951] | 103 | static void garbage_collector(void)
|
---|
| 104 | {
|
---|
[10814] | 105 | int32_t i,j;
|
---|
[8960] | 106 | struct cs_garbage *garbage, *next, *prev, *first;
|
---|
| 107 | set_thread_name(__func__);
|
---|
[10814] | 108 | int32_t timeout_time = 2*cfg.ctimeout/1000+6;
|
---|
| 109 |
|
---|
[8960] | 110 | while(garbage_collector_active)
|
---|
| 111 | {
|
---|
[10814] | 112 | time_t deltime = time(NULL) - timeout_time;
|
---|
| 113 |
|
---|
[8960] | 114 | for(i = 0; i < HASH_BUCKETS; ++i)
|
---|
| 115 | {
|
---|
[10814] | 116 | j = 0;
|
---|
[10817] | 117 | cs_writelock(__func__, &garbage_lock[i]);
|
---|
[8960] | 118 | first = garbage_first[i];
|
---|
[10814] | 119 |
|
---|
| 120 | for(garbage = first, prev = NULL; garbage; prev = garbage, garbage = garbage->next,j++)
|
---|
[8960] | 121 | {
|
---|
[10814] | 122 | if(j==2)
|
---|
| 123 | {
|
---|
| 124 | j++;
|
---|
[10817] | 125 | cs_writeunlock(__func__, &garbage_lock[i]);
|
---|
[10814] | 126 | }
|
---|
| 127 |
|
---|
| 128 | if(garbage->time < deltime) // all following elements are too new
|
---|
[8960] | 129 | {
|
---|
| 130 | if(prev)
|
---|
| 131 | {
|
---|
| 132 | prev->next = NULL;
|
---|
| 133 | }
|
---|
[10814] | 134 | else
|
---|
| 135 | {
|
---|
| 136 | garbage_first[i] = NULL;
|
---|
| 137 | }
|
---|
[8960] | 138 | break;
|
---|
| 139 | }
|
---|
| 140 | }
|
---|
[10814] | 141 |
|
---|
| 142 | if(j<3)
|
---|
[8960] | 143 | {
|
---|
[10817] | 144 | cs_writeunlock(__func__, &garbage_lock[i]);
|
---|
[8960] | 145 | }
|
---|
[8064] | 146 |
|
---|
[9093] | 147 | // list has been taken out before so we don't need a lock here anymore!
|
---|
[8960] | 148 | while(garbage)
|
---|
| 149 | {
|
---|
| 150 | next = garbage->next;
|
---|
[10814] | 151 | free(garbage->data);
|
---|
| 152 | free(garbage);
|
---|
[8960] | 153 | garbage = next;
|
---|
| 154 | }
|
---|
| 155 | }
|
---|
[10817] | 156 | sleepms_on_cond(__func__, &sleep_cond_mutex, &sleep_cond, 500);
|
---|
[8960] | 157 | }
|
---|
| 158 | pthread_exit(NULL);
|
---|
[4296] | 159 | }
|
---|
| 160 |
|
---|
[8951] | 161 | void start_garbage_collector(int32_t debug)
|
---|
| 162 | {
|
---|
[8960] | 163 | garbage_debug = debug;
|
---|
[10814] | 164 | int32_t i;
|
---|
| 165 |
|
---|
[10817] | 166 | SAFE_MUTEX_INIT(&add_lock, NULL);
|
---|
[10814] | 167 |
|
---|
[8960] | 168 | for(i = 0; i < HASH_BUCKETS; ++i)
|
---|
| 169 | {
|
---|
[10817] | 170 | cs_lock_create(__func__, &garbage_lock[i], "garbage_lock", 9000);
|
---|
[4442] | 171 |
|
---|
[8960] | 172 | garbage_first[i] = NULL;
|
---|
| 173 | }
|
---|
[10817] | 174 | cs_pthread_cond_init(__func__, &sleep_cond_mutex, &sleep_cond);
|
---|
[8604] | 175 |
|
---|
[8960] | 176 | garbage_collector_active = 1;
|
---|
[4502] | 177 |
|
---|
[10870] | 178 | int32_t ret = start_thread("garbage", (void *)&garbage_collector, NULL, &garbage_thread, 0, 1);
|
---|
[8960] | 179 | if(ret)
|
---|
| 180 | {
|
---|
| 181 | cs_exit(1);
|
---|
| 182 | }
|
---|
[4296] | 183 | }
|
---|
| 184 |
|
---|
[6901] | 185 | void stop_garbage_collector(void)
|
---|
[4502] | 186 | {
|
---|
[8960] | 187 | if(garbage_collector_active)
|
---|
| 188 | {
|
---|
[10814] | 189 | int32_t i;
|
---|
[7158] | 190 |
|
---|
[8960] | 191 | garbage_collector_active = 0;
|
---|
[10817] | 192 | SAFE_COND_SIGNAL(&sleep_cond);
|
---|
[11246] | 193 | cs_sleepms(300);
|
---|
[10817] | 194 | SAFE_COND_SIGNAL(&sleep_cond);
|
---|
| 195 | SAFE_THREAD_JOIN(garbage_thread, NULL);
|
---|
[8960] | 196 | for(i = 0; i < HASH_BUCKETS; ++i)
|
---|
[10817] | 197 | { cs_writelock(__func__, &garbage_lock[i]); }
|
---|
[7158] | 198 |
|
---|
[8960] | 199 | for(i = 0; i < HASH_BUCKETS; ++i)
|
---|
| 200 | {
|
---|
| 201 | while(garbage_first[i])
|
---|
| 202 | {
|
---|
| 203 | struct cs_garbage *next = garbage_first[i]->next;
|
---|
[9277] | 204 | NULLFREE(garbage_first[i]->data);
|
---|
| 205 | NULLFREE(garbage_first[i]);
|
---|
[8960] | 206 | garbage_first[i] = next;
|
---|
| 207 | }
|
---|
| 208 | }
|
---|
[10814] | 209 |
|
---|
| 210 | for(i = 0; i < HASH_BUCKETS; ++i)
|
---|
| 211 | {
|
---|
[10817] | 212 | cs_writeunlock(__func__, &garbage_lock[i]);
|
---|
| 213 | cs_lock_destroy(__func__, &garbage_lock[i]);
|
---|
[10814] | 214 | }
|
---|
| 215 |
|
---|
| 216 | pthread_mutex_destroy(&add_lock);
|
---|
| 217 | pthread_cond_destroy(&sleep_cond);
|
---|
| 218 | pthread_mutex_destroy(&sleep_cond_mutex);
|
---|
[8960] | 219 | }
|
---|
[4502] | 220 | }
|
---|