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  | }