xref: /minix3/minix/lib/libmthread/misc.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1 #include <minix/mthread.h>
2 #include <stdio.h>
3 #include "global.h"
4 #include "proto.h"
5 
6 /*===========================================================================*
7  *				mthread_debug_f				     *
8  *===========================================================================*/
9 #ifdef MDEBUG
mthread_debug_f(const char * file,int line,const char * msg)10 void mthread_debug_f(const char *file, int line, const char *msg)
11 {
12   /* Print debug message */
13   printf("MTH (%s:%d): %s\n", file, line, msg);
14 }
15 #endif
16 
17 /*===========================================================================*
18  *				mthread_panic_f				     *
19  *===========================================================================*/
20 #ifdef MDEBUG
mthread_panic_f(const char * file,int line,const char * msg)21 void mthread_panic_f(const char *file, int line, const char *msg)
22 {
23   /* Print panic message to stdout and exit */
24   volatile int *sf;
25 
26   sf = NULL;
27 
28   printf("mthread panic (%s:%d): ", file, line);
29   printf("%s", msg);
30   printf("\n");
31   fflush(stdout);	/* Force debug print to screen */
32   *((int *) sf ) = 1;	/* Cause segfault to generate trace */
33   exit(1);
34 }
35 #else
mthread_panic_s(void)36 void mthread_panic_s(void)
37 {
38   /* Silent panic */
39   volatile int *sf;
40 
41   sf = NULL;
42   *((volatile int *) sf ) = 1;	/* Cause segfault to generate trace */
43   exit(1);
44 }
45 #endif
46 
47 
48 /*===========================================================================*
49  *				mthread_verify_f			     *
50  *===========================================================================*/
51 #ifdef MDEBUG
mthread_verify_f(char * file,int line)52 void mthread_verify_f(char *file, int line)
53 {
54   /* Verify library state. It is assumed this function is never called from
55    * a spawned thread, but from the 'main' thread. The library should be
56    * quiescent; no mutexes, conditions, or threads in use. All threads are to
57    * be in DEAD state.
58    */
59   mthread_thread_t t;
60   mthread_tcb_t *tcb;
61   int threads_ok = 1, conditions_ok = 1, mutexes_ok = 1, attributes_ok = 1;
62 
63   for (t = (mthread_thread_t) 0; threads_ok && t < no_threads; t++) {
64   	tcb = mthread_find_tcb(t);
65   	if (tcb->m_state != MS_DEAD) threads_ok = 0;
66   }
67 
68   conditions_ok = mthread_cond_verify();
69   mutexes_ok = mthread_mutex_verify();
70   attributes_ok = mthread_attr_verify();
71 
72   printf("(%s:%d) VERIFY ", file, line);
73   printf("| threads: %s |", (threads_ok ? "ok": "NOT ok"));
74   printf("| cond: %s |", (conditions_ok ? "ok": "NOT ok"));
75   printf("| mutex: %s |", (mutexes_ok ? "ok": "NOT ok"));
76   printf("| attr: %s |", (attributes_ok ? "ok": "NOT ok"));
77   printf("\n");
78 
79   if(!threads_ok || !conditions_ok || !mutexes_ok)
80 	mthread_panic("Library state corrupt\n");
81 }
82 
83 
84 /*===========================================================================*
85  *				mthread_stats				     *
86  *===========================================================================*/
mthread_stats(void)87 void mthread_stats(void)
88 {
89   mthread_thread_t t;
90   mthread_tcb_t *tcb;
91   int st_run, st_dead, st_cond, st_mutex, st_exit;
92   st_run = st_dead = st_cond = st_mutex = st_exit = 0;
93 
94   for (t = (mthread_thread_t) 0; t < no_threads; t++) {
95   	tcb = mthread_find_tcb(t);
96   	switch(tcb->m_state) {
97   		case MS_RUNNABLE: st_run++; break;
98   		case MS_DEAD: st_dead++; break;
99   		case MS_MUTEX: st_mutex++; break;
100   		case MS_CONDITION: st_cond++; break;
101   		case MS_EXITING: st_exit++; break;
102   		default: mthread_panic("Unknown state");
103   	}
104   }
105 
106   printf("Pool: %-5d In use: %-5d R: %-5d D: %-5d M: %-5d C: %-5d E: %-5d\n",
107   	 no_threads, used_threads, st_run, st_dead, st_mutex, st_cond,
108 	 st_exit);
109 }
110 
111 #endif
112 
113 
114 /*===========================================================================*
115  *				mthread_stacktrace			     *
116  *===========================================================================*/
mthread_stacktrace(mthread_thread_t t)117 void mthread_stacktrace(mthread_thread_t t)
118 {
119 #ifdef __i386__ /* stacktrace only implemented on x86 */
120   unsigned long bp, hbp, pc;
121   mthread_tcb_t *tcb;
122   ucontext_t *ctx;
123 
124   tcb = mthread_find_tcb(t);
125   ctx = &tcb->m_context;
126 
127   if (t != MAIN_THREAD && ctx->uc_stack.ss_size == 0)
128 	return; /* no stack, no stacktrace */
129 
130   printf("thread %d: ", t);
131 
132   bp = _UC_MACHINE_EBP(ctx);
133 
134   while (bp) {
135 	pc = ((unsigned long *) bp)[1];
136 	hbp = ((unsigned long *) bp)[0];
137 
138 	printf("0x%lx ", (unsigned long) pc);
139 
140 	if (hbp != 0 && hbp <= bp) {
141 		pc = -1;
142 		printf("0x%lx ", (unsigned long) pc);
143 		break;
144 	}
145 	bp = hbp;
146   }
147 
148   printf("\n");
149 #endif
150 }
151 
152 /*===========================================================================*
153  *				mthread_stacktraces			     *
154  *===========================================================================*/
mthread_stacktraces(void)155 void mthread_stacktraces(void)
156 {
157   mthread_thread_t t;
158 
159   mthread_stacktrace(MAIN_THREAD);
160 
161   for (t = (mthread_thread_t) 0; t < no_threads; t++)
162 	mthread_stacktrace(t);
163 }
164