source: trunk/oscam-garbage.c

Last change on this file was 11473, checked in by Gorgone Impertinence, 10 months ago

big cleanup pack 3

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