source: trunk/oscam-garbage.c@ 8336

Last change on this file since 8336 was 8336, checked in by gf, 9 years ago

gc: Stop using pthread_cancel() to kill gc thread.

pthread_cancel() is dangerous function to use and it is not
supported under Android.

  • Property svn:eol-style set to LF
File size: 4.5 KB
Line 
1#include "globals.h"
2#include "oscam-garbage.h"
3#include "oscam-lock.h"
4#include "oscam-string.h"
5#include "oscam-time.h"
6
7#define HASH_BUCKETS 16
8
9struct cs_garbage {
10 time_t time;
11 void * data;
12 #ifdef WITH_DEBUG
13 char *file;
14 uint16_t line;
15 #endif
16 struct cs_garbage *next;
17};
18
19struct cs_garbage *garbage_first[HASH_BUCKETS];
20struct cs_garbage *garbage_last[HASH_BUCKETS];
21CS_MUTEX_LOCK garbage_lock[HASH_BUCKETS];
22pthread_t garbage_thread;
23int32_t garbage_collector_active = 0;
24int32_t garbage_debug = 0;
25
26#ifdef WITH_DEBUG
27void add_garbage_debug(void *data, char *file, uint16_t line) {
28#else
29void add_garbage(void *data) {
30#endif
31 if (!data)
32 return;
33
34 if (!garbage_collector_active || garbage_debug == 1) {
35 cs_sleepms(1);
36 free(data);
37 return;
38 }
39
40 int32_t bucket = (uintptr_t)data/16 % HASH_BUCKETS;
41 struct cs_garbage *garbage;
42 if (!cs_malloc(&garbage, sizeof(struct cs_garbage))){
43 cs_sleepms(1);
44 free(data);
45 return;
46 }
47 garbage->time = time(NULL);
48 garbage->data = data;
49#ifdef WITH_DEBUG
50 garbage->file = file;
51 garbage->line = line;
52#endif
53 cs_writelock(&garbage_lock[bucket]);
54
55#ifdef WITH_DEBUG
56 if(garbage_debug == 2){
57 struct cs_garbage *garbagecheck = garbage_first[bucket];
58 while(garbagecheck) {
59 if(garbagecheck->data == data) {
60 cs_log("Found a try to add garbage twice. Not adding the element to garbage list...");
61 cs_log("Current garbage addition: %s, line %d.", file, line);
62 cs_log("Original garbage addition: %s, line %d.", garbagecheck->file, garbagecheck->line);
63 cs_writeunlock(&garbage_lock[bucket]);
64 free(garbage);
65 return;
66 }
67 garbagecheck = garbagecheck->next;
68 }
69 }
70#endif
71
72 if(garbage_last[bucket]) garbage_last[bucket]->next = garbage;
73 else garbage_first[bucket] = garbage;
74 garbage_last[bucket] = garbage;
75 cs_writeunlock(&garbage_lock[bucket]);
76}
77
78void garbage_collector(void) {
79 int8_t i;
80 struct cs_garbage *garbage, *next, *prev, *first;
81 set_thread_name(__func__);
82 while (garbage_collector_active) {
83
84 for(i = 0; i < HASH_BUCKETS; ++i){
85 cs_writelock(&garbage_lock[i]);
86 first = garbage_first[i];
87 time_t deltime = time((time_t)0) - (2*cfg.ctimeout/1000 + 1); //clienttimeout +1 second
88 for(garbage = first, prev = NULL; garbage; prev = garbage, garbage = garbage->next) {
89 if (deltime < garbage->time) { // all following elements are too new
90 if(prev){
91 garbage_first[i] = garbage;
92 prev->next = NULL;
93 }
94 break;
95 }
96 }
97 if(!garbage && garbage_first[i]){ // end of list reached and everything is to be cleaned
98 garbage = first;
99 garbage_first[i] = NULL;
100 garbage_last[i] = NULL;
101 } else if(prev) garbage = first; // set back to beginning to cleanup all
102 else garbage = NULL; // garbage not old enough yet => nothing to clean
103 cs_writeunlock(&garbage_lock[i]);
104
105 // list has been taken out before so we don't need a lock here anymore!
106 while(garbage){
107 next = garbage->next;
108 free(garbage->data);
109 free(garbage);
110 garbage = next;
111 }
112 }
113 cs_sleepms(1000);
114 }
115 pthread_exit(NULL);
116}
117
118void start_garbage_collector(int32_t debug) {
119
120 garbage_debug = debug;
121 int8_t i;
122 for(i = 0; i < HASH_BUCKETS; ++i){
123 cs_lock_create(&garbage_lock[i], 5, "garbage_lock");
124
125 garbage_first[i] = NULL;
126 }
127 pthread_attr_t attr;
128 pthread_attr_init(&attr);
129
130 garbage_collector_active = 1;
131
132 pthread_attr_setstacksize(&attr, PTHREAD_STACK_SIZE);
133 int32_t ret = pthread_create(&garbage_thread, &attr, (void*)&garbage_collector, NULL);
134 if(ret){
135 cs_log("ERROR: can't create garbagecollector thread (errno=%d %s)", ret, strerror(ret));
136 pthread_attr_destroy(&attr);
137 cs_exit(1);
138 } else
139 pthread_detach(garbage_thread);
140 pthread_attr_destroy(&attr);
141}
142
143void stop_garbage_collector(void)
144{
145 if (garbage_collector_active) {
146 int8_t i;
147
148 garbage_collector_active = 0;
149 for(i = 0; i < HASH_BUCKETS; ++i)
150 cs_writelock(&garbage_lock[i]);
151
152 for(i = 0; i < HASH_BUCKETS; ++i){
153 while (garbage_first[i]) {
154 struct cs_garbage *next = garbage_first[i]->next;
155 free(garbage_first[i]->data);
156 free(garbage_first[i]);
157 garbage_first[i] = next;
158 }
159 }
160 }
161}
Note: See TracBrowser for help on using the repository browser.