1 | #include "globals.h"
|
---|
2 | #include "oscam-garbage.h"
|
---|
3 |
|
---|
4 | #define HASH_BUCKETS 16
|
---|
5 |
|
---|
6 | struct cs_garbage {
|
---|
7 | time_t time;
|
---|
8 | void * data;
|
---|
9 | #ifdef WITH_DEBUG
|
---|
10 | char *file;
|
---|
11 | uint16_t line;
|
---|
12 | #endif
|
---|
13 | struct cs_garbage *next;
|
---|
14 | };
|
---|
15 |
|
---|
16 | struct cs_garbage *garbage_first[HASH_BUCKETS];
|
---|
17 | CS_MUTEX_LOCK garbage_lock[HASH_BUCKETS];
|
---|
18 | pthread_t garbage_thread;
|
---|
19 | int32_t garbage_collector_active = 0;
|
---|
20 | int32_t garbage_debug = 0;
|
---|
21 |
|
---|
22 | #ifdef WITH_DEBUG
|
---|
23 | void add_garbage_debug(void *data, char *file, uint16_t line) {
|
---|
24 | #else
|
---|
25 | void add_garbage(void *data) {
|
---|
26 | #endif
|
---|
27 | if (!data)
|
---|
28 | return;
|
---|
29 |
|
---|
30 | if (!garbage_collector_active || garbage_debug == 1) {
|
---|
31 | free(data);
|
---|
32 | return;
|
---|
33 | }
|
---|
34 |
|
---|
35 | int32_t bucket = (uintptr_t)data/16 % HASH_BUCKETS;
|
---|
36 | cs_writelock(&garbage_lock[bucket]);
|
---|
37 |
|
---|
38 | #ifdef WITH_DEBUG
|
---|
39 | if(garbage_debug == 2){
|
---|
40 | struct cs_garbage *garbagecheck = garbage_first[bucket];
|
---|
41 | while(garbagecheck) {
|
---|
42 | if(garbagecheck->data == data) {
|
---|
43 | cs_log("Found a try to add garbage twice. Not adding the element to garbage list...");
|
---|
44 | cs_log("Current garbage addition: %s, line %d.", file, line);
|
---|
45 | cs_log("Original garbage addition: %s, line %d.", garbagecheck->file, garbagecheck->line);
|
---|
46 | cs_writeunlock(&garbage_lock[bucket]);
|
---|
47 | return;
|
---|
48 | }
|
---|
49 | garbagecheck = garbagecheck->next;
|
---|
50 | }
|
---|
51 | }
|
---|
52 | #endif
|
---|
53 |
|
---|
54 | struct cs_garbage *garbage;
|
---|
55 | if (!cs_malloc(&garbage, sizeof(struct cs_garbage), -1))
|
---|
56 | {
|
---|
57 | free(data);
|
---|
58 | cs_writeunlock(&garbage_lock[bucket]);
|
---|
59 | return;
|
---|
60 | }
|
---|
61 | garbage->time = time(NULL);
|
---|
62 | garbage->data = data;
|
---|
63 | garbage->next = garbage_first[bucket];
|
---|
64 | #ifdef WITH_DEBUG
|
---|
65 | garbage->file = file;
|
---|
66 | garbage->line = line;
|
---|
67 | #endif
|
---|
68 | garbage_first[bucket] = garbage;
|
---|
69 |
|
---|
70 | cs_writeunlock(&garbage_lock[bucket]);
|
---|
71 | }
|
---|
72 |
|
---|
73 | void garbage_collector(void) {
|
---|
74 | time_t now;
|
---|
75 | int8_t i;
|
---|
76 | struct cs_garbage *garbage, *next, *prev;
|
---|
77 |
|
---|
78 | while (garbage_collector_active) {
|
---|
79 |
|
---|
80 | for(i = 0; i < HASH_BUCKETS; ++i){
|
---|
81 | cs_writelock(&garbage_lock[i]);
|
---|
82 | now = time(NULL);
|
---|
83 |
|
---|
84 | prev = NULL;
|
---|
85 | garbage = garbage_first[i];
|
---|
86 | while (garbage) {
|
---|
87 | next = garbage->next;
|
---|
88 | if (now > (time_t)(garbage->time+2*cfg.ctimeout/1000+1)) { //clienttimeout +1 second
|
---|
89 | free(garbage->data);
|
---|
90 |
|
---|
91 | if (prev)
|
---|
92 | prev->next = next;
|
---|
93 | else
|
---|
94 | garbage_first[i] = next;
|
---|
95 | free(garbage);
|
---|
96 | }
|
---|
97 | else
|
---|
98 | prev = garbage;
|
---|
99 | garbage = next;
|
---|
100 | }
|
---|
101 | cs_writeunlock(&garbage_lock[i]);
|
---|
102 | }
|
---|
103 | cs_sleepms(1000);
|
---|
104 | }
|
---|
105 | pthread_exit(NULL);
|
---|
106 | }
|
---|
107 |
|
---|
108 | void start_garbage_collector(int32_t debug) {
|
---|
109 |
|
---|
110 | garbage_debug = debug;
|
---|
111 | int8_t i;
|
---|
112 | for(i = 0; i < HASH_BUCKETS; ++i){
|
---|
113 | cs_lock_create(&garbage_lock[i], 5, "garbage_lock");
|
---|
114 |
|
---|
115 | garbage_first[i] = NULL;
|
---|
116 | }
|
---|
117 | pthread_attr_t attr;
|
---|
118 | pthread_attr_init(&attr);
|
---|
119 |
|
---|
120 | garbage_collector_active = 1;
|
---|
121 |
|
---|
122 | pthread_attr_setstacksize(&attr, PTHREAD_STACK_SIZE);
|
---|
123 | int32_t ret = pthread_create(&garbage_thread, &attr, (void*)&garbage_collector, NULL);
|
---|
124 | if(ret){
|
---|
125 | cs_log("ERROR: can't create garbagecollector thread (errno=%d %s)", ret, strerror(ret));
|
---|
126 | pthread_attr_destroy(&attr);
|
---|
127 | cs_exit(1);
|
---|
128 | } else
|
---|
129 | pthread_detach(garbage_thread);
|
---|
130 | pthread_attr_destroy(&attr);
|
---|
131 | }
|
---|
132 |
|
---|
133 | void stop_garbage_collector(void)
|
---|
134 | {
|
---|
135 | if (garbage_collector_active) {
|
---|
136 | int8_t i;
|
---|
137 |
|
---|
138 | garbage_collector_active = 0;
|
---|
139 | for(i = 0; i < HASH_BUCKETS; ++i)
|
---|
140 | cs_writelock(&garbage_lock[i]);
|
---|
141 |
|
---|
142 | pthread_cancel(garbage_thread);
|
---|
143 | cs_sleepms(100);
|
---|
144 |
|
---|
145 | for(i = 0; i < HASH_BUCKETS; ++i){
|
---|
146 | while (garbage_first[i]) {
|
---|
147 | struct cs_garbage *next = garbage_first[i]->next;
|
---|
148 | free(garbage_first[i]->data);
|
---|
149 | free(garbage_first[i]);
|
---|
150 | garbage_first[i] = next;
|
---|
151 | }
|
---|
152 | }
|
---|
153 | }
|
---|
154 | }
|
---|