source: trunk/oscam-garbage.c

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

big cleanup pack 3

  • Property svn:eol-style set to LF
File size: 4.5 KB
RevLine 
[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]11struct 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]22static int32_t counter = 0;
23static pthread_mutex_t add_lock;
[8447]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;
[4442]29
[4965]30#ifdef WITH_DEBUG
[10826]31void add_garbage_debug(void *data, char *file, uint32_t line)
[8951]32{
[4965]33#else
[8951]34void 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);
[11473]47
[10814]48    int32_t bucket = counter++;
[11473]49
[10814]50    if(counter >= HASH_BUCKETS)
[8960]51    {
[10814]52        counter = 0;
53    }
[11473]54
[10817]55    SAFE_MUTEX_UNLOCK(&add_lock);
[11473]56
[10814]57    struct cs_garbage *garbage = (struct cs_garbage*)malloc(sizeof(struct cs_garbage));
58    if(garbage == NULL)
59    {
[11473]60        cs_log("*** MEMORY FULL -> FREEING DIRECT MAY LEAD TO INSTABILITY!!! ***");
[9277]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
[11473]94    garbage->next = garbage_first[bucket];
[10814]95    garbage_first[bucket] = garbage;
[11473]96
[10817]97    cs_writeunlock(__func__, &garbage_lock[bucket]);
[4296]98}
99
[8498]100static pthread_cond_t sleep_cond;
[8592]101static pthread_mutex_t sleep_cond_mutex;
[8498]102
[8951]103static 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__);
[11473]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;
[11473]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];
[11473]119
120            for(garbage = first, prev = NULL; garbage; prev = garbage, garbage = garbage->next, j++)
[8960]121            {
[11473]122                if(j == 2)
[10814]123                {
124                    j++;
[10817]125                    cs_writeunlock(__func__, &garbage_lock[i]);
[10814]126                }
127
[11473]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
[11473]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]161void start_garbage_collector(int32_t debug)
162{
[8960]163    garbage_debug = debug;
[10814]164    int32_t i;
[11473]165
[10817]166    SAFE_MUTEX_INIT(&add_lock, NULL);
[11473]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]185void 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);
[11473]196
[8960]197        for(i = 0; i < HASH_BUCKETS; ++i)
[10817]198            { cs_writelock(__func__, &garbage_lock[i]); }
[7158]199
[8960]200        for(i = 0; i < HASH_BUCKETS; ++i)
201        {
202            while(garbage_first[i])
203            {
204                struct cs_garbage *next = garbage_first[i]->next;
[9277]205                NULLFREE(garbage_first[i]->data);
206                NULLFREE(garbage_first[i]);
[8960]207                garbage_first[i] = next;
208            }
209        }
[11473]210
[10814]211        for(i = 0; i < HASH_BUCKETS; ++i)
[11473]212        {
[10817]213            cs_writeunlock(__func__, &garbage_lock[i]);
214            cs_lock_destroy(__func__, &garbage_lock[i]);
[10814]215        }
216
[11473]217        pthread_mutex_destroy(&add_lock);
218        pthread_cond_destroy(&sleep_cond);
[10814]219        pthread_mutex_destroy(&sleep_cond_mutex);
[8960]220    }
[4502]221}
Note: See TracBrowser for help on using the repository browser.