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