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