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