Source File modules/ta/ta.c

    1    | /***************************************
    2    |   $Revision: 1.8 $
    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   | /*++++++++++++++++++++++++++++++++++++++
    37   |
    38   |   Finds a thread by thread_id. Assumes locked list.
    39   |
    40   |   ta_str_t *ta_findonly_l     returns a pointer to the thread's record
    41   |
    42   |   GList **list                thread list
    43   |
    44   |   pthread_t thread_id         thread id
    45   |
    46   |   ++++++++++++++++++++++++++++++++++++++*/
    47   | static
    48   | ta_str_t *ta_findonly_l( GList **list, pthread_t thread_id )
    49   | {
    50   |   GList *item;
    51   |
    52   |   /* try to find first */
    53   |   for(item = g_list_first(*list);
    54   |       item != NULL;
    55   |       item = g_list_next(item)) {
    56   |     ta_str_t *tas = (ta_str_t *) (item->data);
    57   |
    58   |     if( tas->thread_id == thread_id ) {
    59   |       return tas;
    60   |     }
    61   |   }
    62   |   return NULL;
    63   | }
    64   |
    65   |
    66   | /*++++++++++++++++++++++++++++++++++++++
    67   |
    68   |   Finds a thread by thread_id, or creates a new entry if there isn't one.
    69   |   Assumes locked list.
    70   |
    71   |   ta_str_t *ta_findcreate_l   returns a pointer to the thread's record
    72   |
    73   |   GList **list                thread list
    74   |
    75   |   pthread_t thread_id         thread id
    76   |
    77   |   ++++++++++++++++++++++++++++++++++++++*/
    78   | static
    79   | ta_str_t *ta_findcreate_l( GList **list, pthread_t thread_id )
    80   | {
    81   |   ta_str_t *newtas;
    82   |
    83   |   if( (newtas = ta_findonly_l(list, thread_id)) == NULL) {
    84   |
    85   |     /* not found => add */  /* zero everything*/
    86   |     dieif( !NOERR( wr_calloc( (void **) &newtas, 1, sizeof( ta_str_t ))));
    87   |     newtas->thread_id = thread_id;
    88   |
    89   |     *list = g_list_append( *list, newtas );
    90   |   }
    91   |
    92   |   return newtas;
    93   | }
    94   |
    95   |
    96   |
    97   | /*++++++++++++++++++++++++++++++++++++++
    98   |
    99   |   finds and removes an entry for a thread given by thread_id.
    100  |   Assumes locked list.
    101  |
    102  |   GList **list                thread list
    103  |
    104  |   pthread_t thread_id         thread id
    105  |
    106  |   ++++++++++++++++++++++++++++++++++++++*/
    107  | static
    108  | void ta_remove_l(GList **list, pthread_t thread_id )
    109  | {
    110  |  GList *item;
    111  |
    112  |  for(item = g_list_first(*list);
    113  |      item != NULL;
    114  |      item = g_list_next(item)) {
    115  |    ta_str_t *tas = (ta_str_t *) (item->data);
    116  |
    117  |    if( tas->thread_id == thread_id ) {
    118  |      *list = g_list_remove_link(*list, item);
    119  |      wr_clear_list( &item );
    120  |      break;
    121  |    }
    122  |  }
    123  |
    124  |  return;
    125  | }
    126  |
    127  |
    128  | /*++++++++++++++++++++++++++++++++++++++
    129  |
    130  |   sets the activity field in the given thread's record.
    131  |   Truncates the string if too long.
    132  |
    133  |   ta_str_t *tas        pointer to the thread's record
    134  |
    135  |   char *activity       new value for the activity field
    136  |   ++++++++++++++++++++++++++++++++++++++*/
    137  | static
    138  | void ta_setactivity_l(ta_str_t *tas, char *activity)
    139  | {
    140  |   char *nl;
    141  |
    142  |   strncpy(tas->activity, activity, TA_ACT_LEN-1);
    143  |   tas->activity[TA_ACT_LEN]=0;
    144  |   /* convert last newline to a space, if any */
    145  |   if( (nl=strrchr(tas->activity, '\n')) != NULL ) {
    146  |     *nl=' ';
    147  |   }
    148  | }
    149  |
    150  |
    151  | #define TA_HEADER "%-8s %15s %4s %4s %5s %5s %4s %6s %s\n"
    152  | #define TA_FORMAT "%-8s %15s %4d %4d %5.1f %5.1f %4d %6.3f %s\n"
    153  |
    154  |
    155  | /*++++++++++++++++++++++++++++++++++++++
    156  |
    157  |   prints a header for a list of threads to a specified buffer.
    158  |   The output is truncated if the buffer is too small.
    159  |
    160  |   char *buf         pointer to the buffer
    161  |
    162  |   unsigned length   buffer size
    163  |   ++++++++++++++++++++++++++++++++++++++*/
    164  | static
    165  | void ta_print_header(char *buf, unsigned length)
    166  | {
    167  |   snprintf(buf, length, TA_HEADER,
    168  | 	   "type", "from", "sock", "thr", "sess", "task", "#",
    169  | 	   "avg", "current"
    170  | 	   );
    171  | }
    172  |
    173  |
    174  | /*++++++++++++++++++++++++++++++++++++++
    175  |
    176  |   Formats the data from one thread's record to an entry for a list of
    177  |   threads.  Prints to a specified buffer. Calculates the average time
    178  |   spent per event as well as the lifetime of the thread. Checks the
    179  |   address of the peer on the socket. The output is truncated if the
    180  |   buffer is too small.
    181  |
    182  |   ta_str_t *tas        pointer to the thread's record
    183  |
    184  |   char *buf            pointer to the buffer
    185  |
    186  |   unsigned length      buffer size
    187  |
    188  |   ut_timer_t *reftime  current time
    189  |
    190  |   ++++++++++++++++++++++++++++++++++++++*/
    191  | static
    192  | void ta_printone_l(ta_str_t *tas, char *buf, unsigned length,
    193  | 		   ut_timer_t *reftime)
    194  | {
    195  |   float session, task;  /* duration of the session/task */
    196  |   char *address = SK_getpeername(tas->sock); /* allocated! */
    197  |   /* can be NULL for example if the socket has just closed
    198  |      or the file descriptor is not a socket */
    199  |
    200  |   session = UT_timediff( &tas->sessionstart, reftime );
    201  |   task    = UT_timediff( &tas->taskstart, reftime );
    202  |
    203  |   snprintf(buf, length, TA_FORMAT ,
    204  | 	   tas->type,
    205  | 	   address ? address : "",
    206  | 	   tas->sock,
    207  | 	   tas->thread_id,
    208  | 	   session,
    209  | 	   task,
    210  | 	   tas->tasks,
    211  | 	   (tas->tasks > 0) ? session / tas->tasks : 0,
    212  | 	   tas->activity);
    213  |
    214  |   if (address) {
    215  |     wr_free(address);
    216  |   }
    217  | }
    218  |
    219  |
    220  | /*++++++++++++++++++++++++++++++++++++++
    221  |
    222  |   Public adding function - adds the current thread to the list,
    223  |   storing the given socket and type string along.
    224  |
    225  |   int sock      associated socket (if any, or 0 if not)
    226  |
    227  |   char *type    type string
    228  |
    229  |   ++++++++++++++++++++++++++++++++++++++*/
    230  | void TA_add(int sock, char *type)
    231  | {
    232  |   ta_str_t *newtas;
    233  |
    234  |   /* lock the list */
    235  |   pthread_mutex_lock( &ta_mutex );
    236  |
    237  |   /* find/create node and set peer/thread_id */
    238  |   newtas = ta_findcreate_l( &ta_list, pthread_self());
    239  |   newtas->sock = sock;
    240  |   newtas->tasks = 0;
    241  |   newtas->condat = NULL;
    242  |   UT_timeget( &newtas->sessionstart );
    243  |   UT_timeget( &newtas->taskstart ); /* just to get it a reasonable value */
    244  |
    245  |   snprintf(newtas->type, TA_TYPE_LEN, type);
    246  |   ta_setactivity_l(newtas,"--");
    247  |
    248  |   /* unlock */
    249  |   pthread_mutex_unlock( &ta_mutex );
    250  | }
    251  |
    252  |
    253  | /*++++++++++++++++++++++++++++++++++++++
    254  |
    255  |   Public deletion function - deletes the current thread from the list.
    256  |
    257  |   ++++++++++++++++++++++++++++++++++++++*/
    258  | void TA_delete(void)
    259  | {
    260  |   /* lock the list */
    261  |   pthread_mutex_lock( &ta_mutex );
    262  |
    263  |   /* find & remove */
    264  |   ta_remove_l( &ta_list, pthread_self() );
    265  |
    266  |   /* unlock */
    267  |   pthread_mutex_unlock( &ta_mutex );
    268  | }
    269  |
    270  |
    271  | /*++++++++++++++++++++++++++++++++++++++
    272  |
    273  |   Public activity-setting function - sets the current activity string
    274  |   for the current thread.
    275  |
    276  |   char *activity     new value
    277  |
    278  |   ++++++++++++++++++++++++++++++++++++++*/
    279  | void TA_setactivity(char *activity)
    280  | {
    281  |   ta_str_t *newtas;
    282  |
    283  |   /* lock the list */
    284  |   pthread_mutex_lock( &ta_mutex );
    285  |
    286  |   /* find */
    287  |   newtas = ta_findcreate_l( &ta_list, pthread_self());
    288  |
    289  |   /* set the activity field */
    290  |   ta_setactivity_l(newtas, activity);
    291  |
    292  |   /* unlock */
    293  |   pthread_mutex_unlock( &ta_mutex );
    294  | }
    295  |
    296  |
    297  | /*++++++++++++++++++++++++++++++++++++++
    298  |
    299  |   Public condat-setting function - associates a connection data
    300  |   structure with the current thread.
    301  |
    302  |   sk_conn_st *condat    pointer to a connection data structure
    303  |
    304  |   ++++++++++++++++++++++++++++++++++++++*/
    305  | void TA_setcondat(sk_conn_st *condat)
    306  | {
    307  |   ta_str_t *newtas;
    308  |
    309  |   /* lock the list */
    310  |   pthread_mutex_lock( &ta_mutex );
    311  |
    312  |   /* find */
    313  |   newtas = ta_findcreate_l( &ta_list, pthread_self());
    314  |
    315  |   /* set the condat field */
    316  |   newtas->condat = condat;
    317  |
    318  |   /* unlock */
    319  |   pthread_mutex_unlock( &ta_mutex );
    320  | }
    321  |
    322  |
    323  | /*++++++++++++++++++++++++++++++++++++++
    324  |
    325  |    increments the event counter for the current thread.
    326  |
    327  |   ++++++++++++++++++++++++++++++++++++++*/
    328  | void TA_increment(void)
    329  | {
    330  |   ta_str_t *newtas;
    331  |
    332  |   /* lock the list */
    333  |   pthread_mutex_lock( &ta_mutex );
    334  |
    335  |   /* find */
    336  |   newtas = ta_findcreate_l( &ta_list, pthread_self());
    337  |   /* increment task */
    338  |   newtas->tasks++;
    339  |   /* set task starting time */
    340  |   UT_timeget( &newtas->taskstart );
    341  |
    342  |   /* unlock */
    343  |   pthread_mutex_unlock( &ta_mutex );
    344  | }
    345  |
    346  |
    347  | /*++++++++++++++++++++++++++++++++++++++
    348  |
    349  |   resets the time and event counter of a specified thread.
    350  |
    351  |   pthread_t thread_id     thread_id
    352  |
    353  |   ++++++++++++++++++++++++++++++++++++++*/
    354  | void TA_reset_counters(pthread_t thread_id)
    355  | {
    356  |   ta_str_t *tas;
    357  |
    358  |   /* lock the list */
    359  |   pthread_mutex_lock( &ta_mutex );
    360  |
    361  |   if( (tas = ta_findonly_l(&ta_list, thread_id)) != NULL) {
    362  |     UT_timeget( &tas->sessionstart );
    363  |     UT_timeget( &tas->taskstart ); /* just to get it a reasonable value */
    364  |     tas->tasks = 0;
    365  |   }
    366  |
    367  |   pthread_mutex_unlock( &ta_mutex );
    368  | }
    369  |
    370  |
    371  | /*++++++++++++++++++++++++++++++++++++++
    372  |
    373  |   Compiles a list of the threads' data records as text.
    374  |
    375  |   char * TA_tostring      returns an allocated text, must be freed after use.
    376  |
    377  |   ++++++++++++++++++++++++++++++++++++++*/
    378  | char * TA_tostring(void)
    379  | {
    380  |   GList *item;
    381  |   char *bigbuf = NULL;
    382  |   char smallbuf[TA_PRINT_LEN];
    383  |   ut_timer_t reftime;
    384  |
    385  |   ta_print_header(smallbuf, TA_PRINT_LEN);
    386  |   dieif( !NOERR(wr_malloc( (void **) &bigbuf, strlen(smallbuf)+2 )));
    387  |   strcpy(bigbuf, smallbuf);
    388  |   strcat(bigbuf, "\n");
    389  |
    390  |   /* lock the list */
    391  |   pthread_mutex_lock( &ta_mutex );
    392  |
    393  |   /* get reference time */
    394  |   UT_timeget( &reftime );
    395  |
    396  |   /* iterate */
    397  |   for(item = g_list_first(ta_list);
    398  |       item != NULL;
    399  |       item = g_list_next(item)) {
    400  |     ta_str_t *tas = (ta_str_t *) (item->data);
    401  |     unsigned smalllen;
    402  |     unsigned biglen = ( bigbuf == NULL ) ? 0 : strlen(bigbuf);
    403  |
    404  |     ta_printone_l(tas, smallbuf, TA_PRINT_LEN, &reftime);
    405  |     smalllen = strlen(smallbuf);
    406  |
    407  |     dieif( !NOERR(wr_realloc( (void **) &bigbuf, biglen+smalllen+3 )));
    408  |
    409  |     strcat(bigbuf, smallbuf);
    410  |   }
    411  |   /* unlock */
    412  |   pthread_mutex_unlock( &ta_mutex );
    413  |
    414  |   return bigbuf;
    415  | }
    416  |
    417  |
    418  |
    419  | /*++++++++++++++++++++++++++++++++++++++
    420  |
    421  |   Finds a thread of the matching type, socket file descriptor and thread id
    422  |   and executes the watchdog's triggers if it's defined.
    423  |
    424  |   char *type                thread type string
    425  |
    426  |   int sock                  socket #
    427  |
    428  |   pthread_t thread_id       thread id
    429  |
    430  |   ++++++++++++++++++++++++++++++++++++++*/
    431  | void TA_trigger(char *type, int sock, pthread_t thread_id)
    432  | {
    433  |   ta_str_t *tas;
    434  |
    435  |   /* lock the list */
    436  |   pthread_mutex_lock( &ta_mutex );
    437  |
    438  |   if( (tas = ta_findonly_l(&ta_list, thread_id)) != NULL
    439  |       && tas->sock == sock
    440  |       && strcmp(tas->type, type) == 0
    441  |       && tas->condat != NULL
    442  |       && tas->condat->sock == sock
    443  |       ) {
    444  |     SK_watchtrigger(tas->condat);
    445  |   }
    446  |
    447  |   /* unlock */
    448  |   pthread_mutex_unlock( &ta_mutex );
    449  |
    450  | }