1 | /***************************************
2 | $Revision: 1.4 $
3 |
4 | thread accounting (ta). ta.c - functions to keep track of activities
5 | of threads within the server
6 |
7 | Status: NOT REVUED, TESTED, COMPLETE
8 |
9 | Design and implementation by: Marek Bukowy
10 |
11 | ******************/ /******************
12 | Copyright (c) 1999 RIPE NCC
13 |
14 | All Rights Reserved
15 |
16 | Permission to use, copy, modify, and distribute this software and its
17 | documentation for any purpose and without fee is hereby granted,
18 | provided that the above copyright notice appear in all copies and that
19 | both that copyright notice and this permission notice appear in
20 | supporting documentation, and that the name of the author not be
21 | used in advertising or publicity pertaining to distribution of the
22 | software without specific, written prior permission.
23 |
24 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
25 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
26 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
27 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
28 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
29 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 | ***************************************/
31 |
32 | #define TA_IMPL
33 | #include <ta.h>
34 |
35 |
36 | static
37 | ta_str_t *ta_findonly_l( GList **list, pthread_t thread_id )
38 | {
39 | GList *item;
40 |
41 | /* try to find first */
42 | for(item = g_list_first(*list);
43 | item != NULL;
44 | item = g_list_next(item)) {
45 | ta_str_t *tas = (ta_str_t *) (item->data);
46 |
47 | if( tas->thread_id == thread_id ) {
48 | return tas;
49 | }
50 | }
51 | return NULL;
52 | }
53 |
54 | static
55 | ta_str_t *ta_findcreate_l( GList **list, pthread_t thread_id )
56 | {
57 | ta_str_t *newtas;
58 |
59 | if( (newtas = ta_findonly_l(list, thread_id)) == NULL) {
60 |
61 | /* not found => add */ /* zero everything*/
62 | dieif( !NOERR( wr_calloc( (void **) &newtas, 1, sizeof( ta_str_t ))));
63 | newtas->thread_id = thread_id;
64 |
65 | *list = g_list_append( *list, newtas );
66 | }
67 |
68 | return newtas;
69 | }
70 |
71 |
72 | /* find and remove */
73 | static
74 | void ta_remove_l(GList **list, pthread_t thread_id )
75 | {
76 | GList *item;
77 |
78 | for(item = g_list_first(*list);
79 | item != NULL;
80 | item = g_list_next(item)) {
81 | ta_str_t *tas = (ta_str_t *) (item->data);
82 |
83 | if( tas->thread_id == thread_id ) {
84 | *list = g_list_remove_link(*list, item);
85 | wr_clear_list( &item );
86 | break;
87 | }
88 | }
89 |
90 | return;
91 | }
92 |
93 | /* set the activity field */
94 | static
95 | void ta_setactivity_l(ta_str_t *tas, char *activity)
96 | {
97 | char *nl;
98 |
99 | strncpy(tas->activity, activity, TA_ACT_LEN-1);
100 | tas->activity[TA_ACT_LEN]=0;
101 | /* convert last newline to a space, if any */
102 | if( (nl=strrchr(tas->activity, '\n')) != NULL ) {
103 | *nl=' ';
104 | }
105 | }
106 |
107 |
108 | #define TA_HEADER "%-8s %15s %4s %4s %5s %5s %4s %5s %s\n"
109 | #define TA_FORMAT "%-8s %15s %4d %4d %5.1f %5.1f %4d %5.2f %s\n"
110 |
111 | static
112 | void ta_print_header(char *buf, int length)
113 | {
114 | snprintf(buf, length, TA_HEADER,
115 | "type", "from", "sock", "thr", "sess", "task", "#",
116 | "avg", "current"
117 | );
118 | }
119 |
120 | /* fill in one entry */
121 | static
122 | void ta_printone_l(ta_str_t *tas, char *buf, int length,
123 | ut_timer_t *reftime)
124 | {
125 | float session, task; /* duration of the session/task */
126 | char *address = SK_getpeername(tas->sock); /* allocated! */
127 | /* can be NULL for example if the socket has just closed
128 | or the file descriptor is not a socket */
129 |
130 | session = UT_timediff( &tas->sessionstart, reftime );
131 | task = UT_timediff( &tas->taskstart, reftime );
132 |
133 | snprintf(buf, length, TA_FORMAT ,
134 | tas->type,
135 | address ? address : "",
136 | tas->sock,
137 | tas->thread_id,
138 | session,
139 | task,
140 | tas->tasks,
141 | (tas->tasks > 0) ? session / tas->tasks : 0,
142 | tas->activity);
143 |
144 | if (address) {
145 | wr_free(address);
146 | }
147 | }
148 |
149 | /* PUBLIC adding function */
150 | void TA_add(int sock, char *type)
151 | {
152 | ta_str_t *newtas;
153 |
154 | /* lock the list */
155 | pthread_mutex_lock( &ta_mutex );
156 |
157 | /* find/create node and set peer/thread_id */
158 | newtas = ta_findcreate_l( &ta_list, pthread_self());
159 | newtas->sock = sock;
160 | newtas->tasks = 0;
161 | newtas->condat = NULL;
162 | UT_timeget( &newtas->sessionstart );
163 | UT_timeget( &newtas->taskstart ); /* just to get it a reasonable value */
164 |
165 | snprintf(newtas->type, TA_TYPE_LEN, type);
166 | ta_setactivity_l(newtas,"--");
167 |
168 | /* unlock */
169 | pthread_mutex_unlock( &ta_mutex );
170 | }
171 |
172 |
173 | /* PUBLIC deletion function */
174 | void TA_delete(void)
175 | {
176 | /* lock the list */
177 | pthread_mutex_lock( &ta_mutex );
178 |
179 | /* find & remove */
180 | ta_remove_l( &ta_list, pthread_self() );
181 |
182 | /* unlock */
183 | pthread_mutex_unlock( &ta_mutex );
184 | }
185 |
186 |
187 | /* PUBLIC activity-setting function */
188 | void TA_setactivity(char *activity)
189 | {
190 | ta_str_t *newtas;
191 |
192 | /* lock the list */
193 | pthread_mutex_lock( &ta_mutex );
194 |
195 | /* find */
196 | newtas = ta_findcreate_l( &ta_list, pthread_self());
197 |
198 | /* set the activity field */
199 | ta_setactivity_l(newtas, activity);
200 |
201 | /* unlock */
202 | pthread_mutex_unlock( &ta_mutex );
203 | }
204 |
205 | /* PUBLIC condat-setting function */
206 | void TA_setcondat(sk_conn_st *condat)
207 | {
208 | ta_str_t *newtas;
209 |
210 | /* lock the list */
211 | pthread_mutex_lock( &ta_mutex );
212 |
213 | /* find */
214 | newtas = ta_findcreate_l( &ta_list, pthread_self());
215 |
216 | /* set the condat field */
217 | newtas->condat = condat;
218 |
219 | /* unlock */
220 | pthread_mutex_unlock( &ta_mutex );
221 | }
222 |
223 |
224 | void TA_increment(void)
225 | {
226 | ta_str_t *newtas;
227 |
228 | /* lock the list */
229 | pthread_mutex_lock( &ta_mutex );
230 |
231 | /* find */
232 | newtas = ta_findcreate_l( &ta_list, pthread_self());
233 | /* increment task */
234 | newtas->tasks++;
235 | /* set task starting time */
236 | UT_timeget( &newtas->taskstart );
237 |
238 | /* unlock */
239 | pthread_mutex_unlock( &ta_mutex );
240 | }
241 |
242 | char * TA_tostring(void)
243 | {
244 | GList *item;
245 | char *bigbuf = NULL;
246 | char smallbuf[TA_PRINT_LEN];
247 | ut_timer_t reftime;
248 |
249 | ta_print_header(smallbuf, TA_PRINT_LEN);
250 | dieif( !NOERR(wr_malloc( (void **) &bigbuf, strlen(smallbuf)+2 )));
251 | strcpy(bigbuf, smallbuf);
252 | strcat(bigbuf, "\n");
253 |
254 | /* lock the list */
255 | pthread_mutex_lock( &ta_mutex );
256 |
257 | /* get reference time */
258 | UT_timeget( &reftime );
259 |
260 | /* iterate */
261 | for(item = g_list_first(ta_list);
262 | item != NULL;
263 | item = g_list_next(item)) {
264 | ta_str_t *tas = (ta_str_t *) (item->data);
265 | int smalllen;
266 | int biglen = ( bigbuf == NULL ) ? 0 : strlen(bigbuf);
267 |
268 | ta_printone_l(tas, smallbuf, TA_PRINT_LEN, &reftime);
269 | smalllen = strlen(smallbuf);
270 |
271 | dieif( !NOERR(wr_realloc( (void **) &bigbuf, biglen+smalllen+3 )));
272 |
273 | strcat(bigbuf, smallbuf);
274 | }
275 | /* unlock */
276 | pthread_mutex_unlock( &ta_mutex );
277 |
278 | return bigbuf;
279 | }
280 |
281 | /*
282 | find a thread of the given type, socket file descriptor and thread id
283 | and execute the watchdog's triggers if it's defined.
284 | */
285 |
286 | void TA_trigger(char *type, int sock, pthread_t thread_id)
287 | {
288 | ta_str_t *tas;
289 |
290 | /* lock the list */
291 | pthread_mutex_lock( &ta_mutex );
292 |
293 | if( (tas = ta_findonly_l(&ta_list, thread_id)) != NULL
294 | && tas->sock == sock
295 | && strcmp(tas->type, type) == 0
296 | && tas->condat != NULL
297 | && tas->condat->sock == sock
298 | ) {
299 | SK_watchtrigger(tas->condat);
300 | }
301 |
302 | /* unlock */
303 | pthread_mutex_unlock( &ta_mutex );
304 |
305 | }