p/s proxy icon, rework window locks, segv in close_mixers + exportedl, ffmpeg default...
[goodguy/history.git] / cinelerra-5.1 / guicast / bctrace.C
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5
6 #include "bctrace.h"
7
8 #ifdef BOOBY
9 #include <execinfo.h>
10 #define BT_BUF_SIZE 100
11 // booby trap (backtrace)
12 void booby() {
13         printf("BOOBY!\n"); 
14         void *buffer[BT_BUF_SIZE];
15         int nptrs = backtrace(buffer, BT_BUF_SIZE);
16         char **trace = backtrace_symbols(buffer, nptrs);
17         if( !trace ) return;
18         for( int i=0; i<nptrs; ) printf("%s\n", trace[i++]);
19         free(trace);
20 }
21 #endif
22
23 BC_Trace *BC_Trace::global_trace = 0;
24 int trace_memory = 0;
25 int trace_locks = 1;
26
27 BC_Trace::BC_Trace()
28 {
29 }
30 BC_Trace::~BC_Trace()
31 {
32 }
33
34 bc_trace_mutex execution_table;
35 bc_trace_mutex memory_table;
36 bc_trace_mutex lock_table;
37 bc_trace_list  lock_free;
38 bc_trace_mutex file_table;
39
40 // incase lock set after task ends
41 static pthread_t last_lock_thread = 0;
42 static const char *last_lock_title = 0;
43 static const char *last_lock_location = 0;
44
45 trace_item::trace_item(bc_trace_t &t) : table(t) { ++table.size; }
46 trace_item::~trace_item() { --table.size; }
47
48 extern "C" void dump()
49 {
50         BC_Trace::dump_traces();
51         BC_Trace::dump_locks();
52         BC_Trace::dump_buffers();
53 }
54
55 #define TOTAL_TRACES 16
56
57 void BC_Trace::new_trace(const char *text)
58 {
59         if(!global_trace) return;
60         execution_table.lock();
61         execution_item *it;
62         if( execution_table.size >= TOTAL_TRACES ) {
63                 it = (execution_item *)execution_table.first;
64                 execution_table.remove_pointer(it);
65         }
66         else
67                 it = new execution_item();
68         it->set(text);
69         execution_table.append(it);
70         execution_table.unlock();
71 }
72
73 void BC_Trace::new_trace(const char *file, const char *function, int line)
74 {
75         char string[BCTEXTLEN];
76         snprintf(string, BCTEXTLEN, "%s: %s: %d", file, function, line);
77         new_trace(string);
78 }
79
80 void BC_Trace::delete_traces()
81 {
82         if(!global_trace) return;
83         execution_table.lock();
84         execution_table.clear();
85         execution_table.unlock();
86 }
87
88 void BC_Trace::enable_locks()
89 {
90         lock_table.lock();
91         trace_locks = 1;
92         lock_table.unlock();
93 }
94
95 void BC_Trace::disable_locks()
96 {
97         lock_table.lock();
98         trace_locks = 0;
99         while( lock_table.last ) {
100                 lock_item *p = (lock_item*)lock_table.last;
101                 p->info->trace = 0;
102                 lock_table.remove_pointer(p);  lock_free.append(p);
103         }
104         lock_free.clear();
105         lock_table.unlock();
106 }
107
108 // no canceling with lock held
109 void BC_Trace::lock_locks(const char *s)
110 {
111         lock_table.lock();
112         last_lock_thread = pthread_self();
113         last_lock_title = s;
114         last_lock_location = 0;
115 }
116
117 void BC_Trace::unlock_locks()
118 {
119         lock_table.unlock();
120 }
121
122 #define TOTAL_LOCKS 256
123
124 int BC_Trace::set_lock(const char *title, const char *loc, trace_info *info)
125 {
126         if( !global_trace || !trace_locks ) return 0;
127         lock_table.lock();
128         last_lock_thread = pthread_self();
129         last_lock_title = title;
130         last_lock_location = loc;
131         lock_item *it;
132         if( (it=(lock_item*)lock_free.first) != 0 )
133                 lock_free.remove_pointer(it);
134         else if( lock_table.size >= TOTAL_LOCKS ) {
135                 it = (lock_item*)lock_table.first;
136                 lock_table.remove_pointer(it);
137         }
138         else
139                 it = new lock_item();
140         it->set(info, title, loc);
141         lock_table.append(it);
142         info->trace = (void *)it;
143         lock_table.unlock();
144         return it->id;
145 }
146
147 void BC_Trace::set_lock2(int table_id, trace_info *info)
148 {
149         if( !global_trace || !trace_locks ) return;
150         lock_table.lock();
151         lock_item *p = (lock_item *)info->trace;
152         if( !p || p->id != table_id ) {
153                 p = (lock_item*)lock_table.last;
154                 while( p && p->id != table_id ) p = (lock_item*)p->previous;
155         }
156         if( p ) {
157                 info->trace = (void *)p;
158                 p->is_owner = 1;
159                 p->tid = pthread_self();
160         }
161         lock_table.unlock();
162 }
163
164 void BC_Trace::unset_lock2(int table_id, trace_info *info)
165 {
166         if( !global_trace || !trace_locks ) return;
167         lock_table.lock();
168         lock_item *p = (lock_item *)info->trace;
169         if( !p || p->id != table_id ) {
170                 p = (lock_item*)lock_table.last;
171                 while( p && p->id != table_id ) p = (lock_item*)p->previous;
172         }
173         else
174                 info->trace = 0;
175         if( p ) { lock_table.remove_pointer(p);  lock_free.append(p); }
176         lock_table.unlock();
177 }
178
179 void BC_Trace::unset_lock(trace_info *info)
180 {
181         if( !global_trace || !trace_locks ) return;
182         lock_table.lock();
183         lock_item *p = (lock_item *)info->trace;
184         if( !p || p->info!=info || !p->is_owner ) {
185                 p = (lock_item*)lock_table.last;
186                 while( p && ( p->info!=info || !p->is_owner ) ) p = (lock_item*)p->previous;
187         }
188         else
189                 info->trace = 0;
190         if( p ) { lock_table.remove_pointer(p);  lock_free.append(p); }
191         lock_table.unlock();
192 }
193
194
195 void BC_Trace::unset_all_locks(trace_info *info)
196 {
197         if( !global_trace || !trace_locks ) return;
198         lock_table.lock();
199         lock_item *p = (lock_item*)lock_table.first;
200         while( p ) {
201                 lock_item *lp = p;  p = (lock_item*)p->next;
202                 if( lp->info != info ) continue;
203                 lock_table.remove_pointer(lp);  lock_free.append(lp);
204         }
205         lock_table.unlock();
206 }
207
208 void BC_Trace::clear_locks_tid(pthread_t tid)
209 {
210         if( !global_trace || !trace_locks ) return;
211         lock_table.lock();
212         lock_item *p = (lock_item*)lock_table.first;
213         while( p ) {
214                 lock_item *lp = p;  p = (lock_item*)p->next;
215                 if( lp->tid != tid ) continue;
216                 lock_table.remove_pointer(lp);  lock_free.append(lp);
217         }
218         lock_table.unlock();
219 }
220
221
222 void BC_Trace::enable_memory()
223 {
224         trace_memory = 1;
225 }
226
227 void BC_Trace::disable_memory()
228 {
229         trace_memory = 0;
230 }
231
232
233 void BC_Trace::set_buffer(int size, void *ptr, const char* loc)
234 {
235         if(!global_trace) return;
236         if(!trace_memory) return;
237         memory_table.lock();
238 //printf("BC_Trace::set_buffer %p %s\n", ptr, loc);
239         memory_table.append(new memory_item(size, ptr, loc));
240         memory_table.unlock();
241 }
242
243 int BC_Trace::unset_buffer(void *ptr)
244 {
245         if(!global_trace) return 0;
246         if(!trace_memory) return 0;
247         memory_table.lock();
248         memory_item *p = (memory_item*)memory_table.first;
249         for( ; p!=0 && p->ptr!=ptr; p=(memory_item*)p->next );
250         if( p ) delete p;
251         memory_table.unlock();
252         return !p ? 1 : 0;
253 }
254
255 #ifdef TRACE_MEMORY
256
257 void* operator new(size_t size)
258 {
259         void *result = malloc(size);
260         BUFFER(size, result, "new");
261         return result;
262 }
263
264 void* operator new[](size_t size)
265 {
266         void *result = malloc(size);
267         BUFFER(size, result, "new []");
268         return result;
269 }
270
271 void operator delete(void *ptr)
272 {
273         UNBUFFER(ptr);
274         free(ptr);
275 }
276
277 void operator delete[](void *ptr)
278 {
279         UNBUFFER(ptr);
280         free(ptr);
281 }
282
283 #endif
284
285 void BC_Trace::dump_traces(FILE *fp)
286 {
287 // Dump trace table
288         for( trace_item *tp=execution_table.first; tp!=0; tp=tp->next ) {
289                 execution_item *p=(execution_item*)tp;
290                 fprintf(fp,"    %s\n", (char*)p->value);
291         }
292 }
293
294 void BC_Trace::dump_locks(FILE *fp)
295 {
296 // Dump lock table
297 #ifdef TRACE_LOCKS
298         fprintf(fp,"signal_entry: lock table size=%d\n", lock_table.size);
299         for( trace_item *tp=lock_table.first; tp!=0; tp=tp->next ) {
300                 lock_item *p=(lock_item*)tp;
301                 fprintf(fp,"    %p %s %s %p%s\n", p->info, p->title,
302                         p->loc, (void*)p->tid, p->is_owner ? " *" : "");
303         }
304 #endif
305 }
306
307 void BC_Trace::dump_buffers(FILE *fp)
308 {
309 #ifdef TRACE_MEMORY
310         memory_table.lock();
311 // Dump buffer table
312         fprintf(fp,"BC_Trace::dump_buffers: buffer table size=%d\n", memory_table.size);
313         for( trace_item *tp=memory_table.first; tp!=0; tp=tp->next ) {
314                 memory_item *p=(memory_item*)tp;
315                 fprintf(fp,"    %d %p %s\n", p->size, p->ptr, p->loc);
316         }
317         memory_table.unlock();
318 #endif
319 }
320
321 void BC_Trace::delete_temps()
322 {
323         file_table.lock();
324         if( file_table.size )
325                 printf("BC_Trace::delete_temps: deleting %d temp files\n", file_table.size);
326         while( file_table.first ) {
327                 file_item *p = (file_item*)file_table.first;
328                 printf("    %s\n", p->value);
329                 ::remove(p->value);
330                 delete p;
331         }
332         file_table.unlock();
333 }
334
335 void BC_Trace::reset_locks()
336 {
337         lock_table.unlock();
338 }
339
340 void BC_Trace::set_temp(char *string)
341 {
342         file_table.lock();
343         file_item *it = new file_item();
344         it->set(string);
345         file_table.append(it);
346         file_table.unlock();
347 }
348
349 void BC_Trace::unset_temp(char *string)
350 {
351         file_table.lock();
352         file_item *p = (file_item *)file_table.last;
353         for( ; p!=0 && strcmp(p->value,string); p=(file_item*)p->previous );
354         if( p ) delete p;
355         file_table.unlock();
356 }
357
358
359 #ifdef TRACE_THREADS
360
361 TheLock TheLocker::the_lock;
362 TheList TheList::the_list;
363
364 int lock_item::table_id = 0;
365
366 void TheList::dbg_add(pthread_t tid, pthread_t owner, const char *nm)
367 {
368         TheLocker the_locker;
369         int i = the_list.size();
370         while( --i >= 0 && !(the_list[i]->tid == tid && the_list[i]->owner == owner) );
371         if( i >= 0 ) {
372                 printf("dbg_add, dup %016lx %s %s\n",
373                         (unsigned long)tid, nm, the_list[i]->name);
374                 return;
375         }
376         the_list.append(new TheDbg(tid, owner, nm));
377 }
378
379 void TheList::dbg_del(pthread_t tid)
380 {
381         TheLocker the_locker;
382         int i = the_list.size();
383         while( --i >= 0 && the_list[i]->tid != tid );
384         if( i < 0 ) {
385                 printf("dbg_del, mis %016lx\n",(unsigned long)tid);
386                 return;
387         }
388         the_list.remove_object_number(i);
389 }
390
391
392 void TheList::dump_threads(FILE *fp)
393 {
394         int i = the_list.size();
395         while( --i >= 0 ) {
396                 fprintf(fp, "thread 0x%012lx, owner 0x%012lx, %s\n",
397                         (unsigned long)the_list[i]->tid, (unsigned long)the_list[i]->owner,
398                         the_list[i]->name);
399         }
400 }
401
402 #else
403 #define dbg_add(t, o, nm) do {} while(0)
404 #define dbg_del(t) do {} while(0)
405 void TheList::dump_threads(FILE *fp)
406 {
407 }
408 #endif
409
410 void BC_Trace::dump_threads(FILE *fp)
411 {
412         TheList::dump_threads(fp);
413 }
414
415
416 void BC_Trace::dump_shm_stat(const char *fn, FILE *fp)
417 {
418         char path[BCTEXTLEN];
419         sprintf(path, "/proc/sys/kernel/%s",fn);
420         FILE *sfp = fopen(path,"r");
421         if( !sfp ) return;
422         uint64_t v = 0;
423         fscanf(sfp, "%ju", &v);
424         fclose(sfp);
425         fprintf(fp, "%s = %ju\n", fn, v);
426 }
427
428 void BC_Trace::dump_shm_stats(FILE *fp)
429 {
430         dump_shm_stat("shmall", fp);
431         dump_shm_stat("shmmax", fp);
432         dump_shm_stat("shmmni", fp);
433         FILE *sfp = fopen("/proc/sysvipc/shm","r");
434         if( !sfp ) return;
435         char line[BCTEXTLEN];
436         int pid = getpid();
437         if( !fgets(line,sizeof(line), sfp) ) return;
438         int64_t used = 0, other = 0;
439         int n_used = 0, n_other = 0;
440         while( fgets(line,sizeof(line), sfp) ) {
441                 int key, shmid, perms, cpid, lpid, uid, gid, cuid, cgid;
442                 int64_t size, nattch, atime, dtime, ctime, rss, swap;
443                 if( sscanf(line,
444                         "%d %d %o %ju %u %u %ju %u %u %u %u %ju %ju %ju %ju %ju",
445                         &key, &shmid, &perms, &size, &cpid, &lpid, &nattch,
446                         &uid, &gid, &cuid, &cgid, &atime, &dtime, &ctime,
447                         &rss, &swap) != 16 ) break;
448                 if( cpid == pid ) {
449                         used += size;
450                         ++n_used;
451                 }
452                 else {
453                         other += size;
454                         ++n_other;
455                 }
456         }
457         fclose(sfp);
458         fprintf(fp, "shmused = %jd (%d items)\n", used, n_used);
459         fprintf(fp, "shmother = %jd (%d items)\n", other, n_other);
460 }
461