1    | /***************************************
2    |   $Revision: 1.2 $
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   | static
36   | ta_str_t *ta_findcreate_l( GList **list, pthread_t thread_id )
37   | {
38   |   GList *item;
39   |   ta_str_t *newtas;
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   |   
52   |   /* not found => add */  /* zero everything*/
53   |   dieif( !NOERR( wr_calloc( (void **) &newtas, 1, sizeof( ta_str_t ))));
54   |   newtas->thread_id = thread_id;
55   | 
56   |   *list = g_list_append( *list, newtas );
57   | 
58   |   return newtas;
59   | }
60   | 
61   | 
62   | /* find and remove */
63   | static
64   | void ta_remove_l(GList **list, pthread_t thread_id )
65   | { 
66   |  GList *item;
67   | 
68   |  for(item = g_list_first(*list);
69   |      item != NULL;
70   |      item = g_list_next(item)) {
71   |    ta_str_t *tas = (ta_str_t *) (item->data);
72   | 
73   |    if( tas->thread_id == thread_id ) {
74   |      *list = g_list_remove_link(*list, item);
75   |      wr_clear_list( &item );
76   |      break;
77   |    }
78   |  }
79   |    
80   |  return;
81   | }
82   | 
83   | /* set the activity field */
84   | static
85   | void ta_setactivity_l(ta_str_t *tas, char *activity)
86   | {
87   |   char *nl;
88   | 
89   |   strncpy(tas->activity, activity, TA_ACT_LEN-1);
90   |   tas->activity[TA_ACT_LEN]=0;
91   |   /* convert last newline to a space, if any */
92   |   if( (nl=strrchr(tas->activity, '\n')) != NULL ) {
93   |     *nl=' ';
94   |   }
95   | }
96   | 
97   | 
98   | #define TA_HEADER "%-8s %15s %4s %4s %5s %5s %4s %5s %s\n"
99   | #define TA_FORMAT "%-8s %15s %4d %4d %5.1f %5.1f %4d %5.2f %s\n"
100  | 
101  | static 
102  | void ta_print_header(char *buf, int length)
103  | {
104  |   snprintf(buf, length, TA_HEADER,
105  | 	   "type", "from", "sock", "thr", "sess", "task", "#", 
106  | 	   "avg", "current"
107  | 	   ); 
108  | }
109  | 
110  | /* fill in one entry */
111  | static
112  | void ta_printone_l(ta_str_t *tas, char *buf, int length, 
113  | 		   ut_timer_t *reftime)
114  | {
115  |   float session, task;  /* duration of the session/task */
116  |   char *address = SK_getpeername(tas->sock); /* allocated! */
117  |   /* can be NULL for example if the socket has just closed
118  |      or the file descriptor is not a socket */
119  | 
120  |   session = UT_timediff( &tas->sessionstart, reftime );
121  |   task    = UT_timediff( &tas->taskstart, reftime );
122  | 
123  |   snprintf(buf, length, TA_FORMAT ,
124  | 	   tas->type,
125  | 	   address ? address : "", 
126  | 	   tas->sock, 
127  | 	   tas->thread_id, 
128  | 	   session,
129  | 	   task,
130  | 	   tas->tasks,
131  | 	   (tas->tasks > 0) ? session / tas->tasks : 0,
132  | 	   tas->activity);
133  |   
134  |   if (address) {
135  |     wr_free(address);
136  |   }
137  | }
138  | 
139  | /* PUBLIC adding function */
140  | void TA_add(int sock, char *type)
141  | {
142  |   ta_str_t *newtas;
143  |   
144  |   /* lock the list */
145  |   pthread_mutex_lock( &ta_mutex );
146  |   
147  |   /* find/create node and set peer/thread_id */
148  |   newtas = ta_findcreate_l( &ta_list, pthread_self());
149  |   newtas->sock = sock;
150  |   newtas->tasks = 0;
151  |   UT_timeget( &newtas->sessionstart );
152  |   UT_timeget( &newtas->taskstart ); /* just to get it a reasonable value */
153  | 
154  |   snprintf(newtas->type, TA_TYPE_LEN, type);
155  |   ta_setactivity_l(newtas,"--");
156  |   
157  |   /* unlock */
158  |   pthread_mutex_unlock( &ta_mutex );
159  | }
160  | 
161  | 
162  | /* PUBLIC deletion function */
163  | void TA_delete(void)
164  | {
165  |   /* lock the list */
166  |   pthread_mutex_lock( &ta_mutex );
167  |   
168  |   /* find & remove */
169  |   ta_remove_l( &ta_list, pthread_self() );
170  |   
171  |   /* unlock */
172  |   pthread_mutex_unlock( &ta_mutex );
173  | }
174  | 
175  | 
176  | /* PUBLIC activity-setting function */
177  | void TA_setactivity(char *activity)
178  | {
179  |   ta_str_t *newtas;
180  | 
181  |   /* lock the list */
182  |   pthread_mutex_lock( &ta_mutex );
183  |   
184  |   /* find */
185  |   newtas = ta_findcreate_l( &ta_list, pthread_self());
186  |   
187  |   /* set the activity field */
188  |   ta_setactivity_l(newtas, activity);
189  | 
190  |   /* unlock */
191  |   pthread_mutex_unlock( &ta_mutex );
192  | }
193  | 
194  | void TA_increment(void)
195  | {
196  |   ta_str_t *newtas;
197  | 
198  |   /* lock the list */
199  |   pthread_mutex_lock( &ta_mutex );
200  |   
201  |   /* find */
202  |   newtas = ta_findcreate_l( &ta_list, pthread_self());
203  |   /* increment task */
204  |   newtas->tasks++;
205  |   /* set task starting time */
206  |   UT_timeget( &newtas->taskstart );
207  | 
208  |   /* unlock */
209  |   pthread_mutex_unlock( &ta_mutex );
210  | }
211  | 
212  | char * TA_tostring(void)
213  | {
214  |   GList *item;
215  |   char *bigbuf = NULL;
216  |   char smallbuf[TA_PRINT_LEN];
217  |   ut_timer_t reftime;
218  | 
219  |   ta_print_header(smallbuf, TA_PRINT_LEN);
220  |   dieif( !NOERR(wr_realloc( (void **) &bigbuf, strlen(smallbuf)+2 )));
221  |   strcat(bigbuf, smallbuf);
222  |   strcat(bigbuf, "\n");
223  |   
224  |   /* lock the list */
225  |   pthread_mutex_lock( &ta_mutex );
226  |   
227  |   /* get reference time */
228  |   UT_timeget( &reftime );
229  |   
230  |   /* iterate */
231  |   for(item = g_list_first(ta_list);
232  |       item != NULL;
233  |       item = g_list_next(item)) {
234  |     ta_str_t *tas = (ta_str_t *) (item->data);
235  |     int smalllen;
236  |     int biglen = ( bigbuf == NULL ) ? 0 : strlen(bigbuf);
237  | 
238  |     ta_printone_l(tas, smallbuf, TA_PRINT_LEN, &reftime);
239  |     smalllen = strlen(smallbuf);
240  | 
241  |     dieif( !NOERR(wr_realloc( (void **) &bigbuf, biglen+smalllen+3 )));
242  |     
243  |     strcat(bigbuf, smallbuf);
244  |   }
245  |   /* unlock */
246  |   pthread_mutex_unlock( &ta_mutex );
247  |   
248  |   return bigbuf;
249  | }