Changeset 5754


Ignore:
Timestamp:
May 6, 2008, 3:52:57 PM (14 years ago)
Author:
charles
Message:

#915: Does too many wake-ups when idle

Location:
trunk/libtransmission
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/port-forwarding.c

    r5619 r5754  
    189189    s->natpmp       = tr_natpmpInit();
    190190    s->upnp         = tr_upnpInit();
    191     s->pulseTimer   = tr_timerNew( h, sharedPulse, s, 500 );
     191    s->pulseTimer   = tr_timerNew( h, sharedPulse, s, 1000 );
    192192    s->isEnabled    = isEnabled ? 1 : 0;
    193193    s->upnpStatus   = TR_NAT_TRAVERSAL_UNMAPPED;
  • trunk/libtransmission/trevent.c

    r5683 r5754  
    1212
    1313#include <assert.h>
     14#include <errno.h>
    1415#include <stdlib.h>
    1516#include <string.h>
     
    1819#include <signal.h>
    1920
     21#ifdef WIN32
     22  #include <fcntl.h>
     23  #define pipe(f) _pipe(f, 1000, _O_BINARY)
     24#else
     25  #include <unistd.h>
     26#endif
     27
    2028#include <event.h>
    21 #include <evhttp.h>
    2229
    2330#include "transmission.h"
    24 #include "list.h"
    2531#include "platform.h"
    2632#include "trevent.h"
    2733#include "utils.h"
    2834
    29 /* #define DEBUG */
    30 #ifdef DEBUG
    31 #include <stdio.h>
    32 #undef tr_dbg
    33 #define tr_dbg( a, b... ) fprintf(stderr, a "\n", ##b )
    34 #endif
    35 
    3635/***
    3736****
     
    4039typedef struct tr_event_handle
    4140{
     41    uint8_t die;
     42    int fds[2];
    4243    tr_lock * lock;
    4344    tr_handle * h;
    4445    tr_thread * thread;
    45     tr_list * commands;
    4646    struct event_base * base;
    47     struct event pulse;
    48     struct timeval pulseInterval;
    49     uint8_t die;
    50 
    51     int timerCount;
     47    struct event pipeEvent;
    5248}
    5349tr_event_handle;
    54 
    55 #ifdef DEBUG
    56 static int reads = 0;
    57 static int writes = 0;
    58 #endif
    59 
    60 enum mode
    61 {
    62     TR_EV_TIMER_ADD,
    63     TR_EV_EXEC
    64 };
    6550
    6651typedef int timer_func(void*);
     
    7661};
    7762
    78 struct tr_event_command
    79 {
    80     int mode;
    81 
    82     struct tr_timer * timer;
    83 
    84     struct evhttp_connection * evcon;
    85     struct evhttp_request * req;
    86     enum evhttp_cmd_type evtype;
    87     char * uri;
    88 
    89     struct bufferevent * bufev;
    90     short enable;
    91     short disable;
    92     char * buf;
    93     size_t buflen;
    94 
    95     void (*func)( void* );
     63struct tr_run_data
     64{
     65    void (*func)( void * );
    9666    void * user_data;
    9767};
    9868
    99 static void
    100 pumpList( int i UNUSED, short s UNUSED, void * veh )
    101 {
     69#define dbgmsg(fmt...) tr_deepLog( __FILE__, __LINE__, "event", ##fmt )
     70
     71static void
     72readFromPipe( int fd, short eventType, void * veh )
     73{
     74    char ch;
     75    int ret;
    10276    tr_event_handle * eh = veh;
    103     int doDie;
    104 
    105     for( ;; )
    106     {
    107         struct tr_event_command * cmd;
    108 
    109         doDie = eh->die && !eh->timerCount;
    110         if( doDie )
    111             break;
    112 
    113         /* get the next command */
    114         tr_lockLock( eh->lock );
    115         cmd = tr_list_pop_front( &eh->commands );
    116         tr_lockUnlock( eh->lock );
    117         if( cmd == NULL )
    118             break;
    119 
    120         /* process the command */
    121         switch( cmd->mode )
    122         {
    123             case TR_EV_TIMER_ADD:
    124                 evtimer_add( &cmd->timer->event, &cmd->timer->tv );
    125                 ++eh->timerCount;
    126                 break;
    127 
    128             case TR_EV_EXEC:
    129                 (cmd->func)( cmd->user_data );
    130                 break;
    131 
    132             default:
    133                 assert( 0 && "unhandled command type!" );
     77    dbgmsg( "readFromPipe: eventType is %hd", eventType );
     78
     79    /* read the command type */
     80    ch = '\0';
     81    do {
     82        ret = read( fd, &ch, 1 );
     83    } while( !eh->die && ret<0 && errno==EAGAIN );
     84    dbgmsg( "command is [%c], ret is %d, errno is %d", ch, ret, (int)errno );
     85
     86    switch( ch )
     87    {
     88        case 'r': /* run in libevent thread */
     89        {
     90            struct tr_run_data data;
     91            const size_t nwant = sizeof( data );
     92            const ssize_t ngot = read( fd, &data, nwant );
     93            if( !eh->die && ( ngot == (ssize_t)nwant ) ) {
     94                dbgmsg( "invoking function in libevent thread" );
     95                (data.func)( data.user_data );
     96            }
     97            break;
    13498        }
    135 
    136         /* cleanup */
    137         tr_free( cmd );
    138     }
    139 
    140     if( !doDie )
    141         evtimer_add( &eh->pulse, &eh->pulseInterval );
    142     else {
    143         assert( eh->timerCount ==  0 );
    144         event_del( &eh->pulse );
     99        case 't': /* create timer */
     100        {
     101            tr_timer * timer;
     102            const size_t nwant = sizeof( timer );
     103            const ssize_t ngot = read( fd, &timer, nwant );
     104            if( !eh->die && ( ngot == (ssize_t)nwant ) ) {
     105                dbgmsg( "adding timer in libevent thread" );
     106                evtimer_add( &timer->event, &timer->tv );
     107            }
     108            break;
     109        }
     110        case '\0': /* eof */
     111        {
     112            dbgmsg( "pipe eof reached... removing event listener" );
     113            event_del( &eh->pipeEvent );
     114            break;
     115        }
     116        default:
     117        {
     118            assert( 0 && "unhandled command type!" );
     119            break;
     120        }
    145121    }
    146122}
     
    167143
    168144    eh->base = event_init( );
     145    eh->h->events = eh;
    169146    event_set_log_callback( logFunc );
    170     evtimer_set( &eh->pulse, pumpList, veh );
    171     evtimer_add( &eh->pulse, &eh->pulseInterval );
    172     eh->h->events = eh;
     147
     148    /* listen to the pipe's read fd */
     149    event_set( &eh->pipeEvent, eh->fds[0], EV_READ|EV_PERSIST, readFromPipe, veh );
     150    event_add( &eh->pipeEvent, NULL );
    173151
    174152    event_dispatch( );
     
    176154    tr_lockFree( eh->lock );
    177155    event_base_free( eh->base );
    178 
    179156    eh->h->events = NULL;
    180 
    181157    tr_free( eh );
    182158    tr_dbg( "Closing libevent thread" );
     
    190166    eh = tr_new0( tr_event_handle, 1 );
    191167    eh->lock = tr_lockNew( );
     168    pipe( eh->fds );
    192169    eh->h = handle;
    193     eh->pulseInterval = tr_timevalMsec( 100 );
    194170    eh->thread = tr_threadNew( libeventThreadFunc, eh, "libeventThreadFunc" );
    195171}
     
    198174tr_eventClose( tr_handle * handle )
    199175{
    200     tr_event_handle * eh = handle->events;
    201 
    202     tr_lockLock( eh->lock );
    203     tr_list_free( &eh->commands, tr_free );
    204     eh->die = TRUE;
    205     tr_lockUnlock( eh->lock );
     176    handle->events->die = TRUE;
     177    tr_deepLog( __FILE__, __LINE__, NULL, "closing trevent pipe" );
     178    close( handle->events->fds[1] );
    206179}
    207180
     
    210183**/
    211184
    212 static void
    213 pushList( struct tr_event_handle * eh, struct tr_event_command * command )
    214 {
    215     tr_lockLock( eh->lock );
    216     tr_list_append( &eh->commands, command );
    217     tr_lockUnlock( eh->lock );
    218 }
    219 
    220185int
    221186tr_amInEventThread( struct tr_handle * handle )
     
    228193**/
    229194
    230 static int
    231 timerCompareFunc( const void * va, const void * vb )
    232 {
    233     const struct tr_event_command * a = va;
    234     const struct tr_timer * b = vb;
    235     return a->timer == b ? 0 : 1;
    236 }
    237 
    238195static void
    239196timerCallback( int fd UNUSED, short event UNUSED, void * vtimer )
     
    241198    int more;
    242199    struct tr_timer * timer = vtimer;
    243     void * del;
    244 
    245     del = tr_list_remove( &timer->eh->commands, timer, timerCompareFunc );
    246 
    247     if( del != NULL ) /* there's a TIMER_DEL command queued for this timer... */
    248         more = FALSE;
    249     else {
    250         timer->inCallback = 1;
    251         more = (*timer->func)( timer->user_data );
    252         timer->inCallback = 0;
    253     }
     200
     201    timer->inCallback = 1;
     202    more = (*timer->func)( timer->user_data );
     203    timer->inCallback = 0;
    254204
    255205    if( more )
     
    257207    else
    258208        tr_timerFree( &timer );
    259 
    260     tr_free( del );
    261209}
    262210
     
    272220
    273221    /* destroy the timer directly or via the command queue */
    274     if( timer!=NULL && !timer->inCallback ) {
    275         void * del;
     222    if( timer && !timer->inCallback )
     223    {
    276224        assert( tr_amInEventThread( timer->eh->h ) );
    277         del = tr_list_remove( &timer->eh->commands, timer, timerCompareFunc );
    278         --timer->eh->timerCount;
    279225        event_del( &timer->event );
    280226        tr_free( timer );
    281         tr_free( del );
    282227    }
    283228}
     
    296241    evtimer_set( &timer->event, timerCallback, timer );
    297242
    298     if( tr_amInThread( handle->events->thread ) ) {
     243    if( tr_amInThread( handle->events->thread ) )
     244    {
    299245        evtimer_add( &timer->event,  &timer->tv );
    300         ++handle->events->timerCount;
    301     } else {
    302         struct tr_event_command * cmd = tr_new0( struct tr_event_command, 1 );
    303         cmd->mode = TR_EV_TIMER_ADD;
    304         cmd->timer = timer;
    305         pushList( handle->events, cmd );
     246    }
     247    else
     248    {
     249        const char ch = 't';
     250        int fd = handle->events->fds[1];
     251        tr_lock * lock = handle->events->lock;
     252
     253        tr_lockLock( lock );
     254        write( fd, &ch, 1 );
     255        write( fd, &timer, sizeof(timer) );
     256        tr_lockUnlock( lock );
    306257    }
    307258
     
    315266{
    316267    if( tr_amInThread( handle->events->thread ) )
     268    {
    317269        (func)( user_data );
    318     else {
    319         struct tr_event_command * cmd = tr_new0( struct tr_event_command, 1 );
    320         cmd->mode = TR_EV_EXEC;
    321         cmd->func = func;
    322         cmd->user_data = user_data;
    323         pushList( handle->events, cmd );
    324     }
    325 }
     270    }
     271    else
     272    {
     273        const char ch = 'r';
     274        int fd = handle->events->fds[1];
     275        tr_lock * lock = handle->events->lock;
     276        struct tr_run_data data;
     277
     278        tr_lockLock( lock );
     279        write( fd, &ch, 1 );
     280        data.func = func;
     281        data.user_data = user_data;
     282        write( fd, &data, sizeof(data) );
     283        tr_lockUnlock( lock );
     284    }
     285}
  • trunk/libtransmission/trevent.h

    r4404 r5754  
    2323void tr_eventClose( struct tr_handle * tr_handle );
    2424
    25 /**
    26 **/
    27 
    28 struct event;
    29 enum evhttp_cmd_type;
    30 struct evhttp_request;
    31 struct evhttp_connection;
    32 struct bufferevent;
    33 
    34 /**
    35 ***
    36 **/
    3725
    3826typedef struct tr_timer  tr_timer;
  • trunk/libtransmission/web.c

    r5714 r5754  
    1111 */
    1212
     13#include <assert.h>
    1314#include <stdlib.h> /* bsearch */
    1415
     
    2728      LIBCURL_VERSION_PATCH >= (micro)))
    2829
    29 //#if CURL_CHECK_VERSION(7,16,0)
    30 //#define USE_CURL_MULTI_SOCKET
    31 //#else
    32 #define PULSE_MSEC 150
    33 //#endif
     30#define PULSE_MSEC 500
    3431
    3532#define dbgmsg(fmt...) tr_deepLog( __FILE__, __LINE__, "web", ##fmt )
     
    3734struct tr_web
    3835{
     36    unsigned int dying     : 1;
     37    unsigned int running   : 1;
     38    int remain;
    3939    CURLM * cm;
    4040    tr_session * session;
    41     int remain;
    4241    struct event timer;
    4342};
     
    10099    CURLMcode rc;
    101100    do {
    102 #ifdef USE_CURL_MULTI_SOCKET
    103         rc = curl_multi_socket_all( web->cm, &unused );
    104 #else
    105101        rc = curl_multi_perform( web->cm, &unused );
    106 #endif
    107102    } while( rc == CURLM_CALL_MULTI_PERFORM );
    108103    if ( rc == CURLM_OK  )
     
    121116
    122117static void
     118ensureTimerIsRunning( tr_web * web )
     119{
     120    if( !web->running )
     121    {
     122        struct timeval tv = tr_timevalMsec( PULSE_MSEC );
     123        dbgmsg( "starting web timer" );
     124        web->running = 1;
     125        evtimer_add( &web->timer, &tv );
     126    }
     127}
     128
     129static void
    123130addTask( void * vtask )
    124131{
     
    129136        struct tr_web * web = task->session->web;
    130137        CURL * ch;
     138
     139        ensureTimerIsRunning( web );
    131140
    132141        ++web->remain;
     
    147156        curl_easy_setopt( ch, CURLOPT_ENCODING, "" );
    148157        curl_multi_add_handle( web->cm, ch );
    149 
    150         pump( web );
    151158    }
    152159}
     
    175182}
    176183
    177 #ifdef USE_CURL_MULTI_SOCKET
    178 
    179 /* libevent says that sock is ready to be processed, so tell libcurl */
    180 static void
    181 ev_sock_cb( int sock, short action, void * vweb )
     184static void
     185webDestroy( tr_web * web )
     186{
     187    dbgmsg( "deleting web timer" );
     188    assert( !web->running );
     189    evtimer_del( &web->timer );
     190    curl_multi_cleanup( web->cm );
     191    tr_free( web );
     192}
     193
     194static void
     195pulse( int socket UNUSED, short action UNUSED, void * vweb )
    182196{
    183197    tr_web * web = vweb;
    184     CURLMcode rc;
    185     int mask, unused;
    186 
    187     switch (action & (EV_READ|EV_WRITE)) {
    188         case EV_READ: mask = CURL_CSELECT_IN; break;
    189         case EV_WRITE: mask = CURL_CSELECT_OUT; break;
    190         case EV_READ|EV_WRITE: mask = CURL_CSELECT_IN|CURL_CSELECT_OUT; break;
    191         default: tr_err( "Unknown event %hd\n", action ); return;
    192     }
    193 
    194     do {
    195         rc = curl_multi_socket_action( web->cm, sock, mask, &unused );
    196     } while( rc == CURLM_CALL_MULTI_PERFORM );
    197     if ( rc == CURLM_OK  )
    198         processCompletedTasks( web );
    199     else
    200         tr_err( "%s (%d)", curl_multi_strerror(rc), (int)sock );
    201 
    202 }
    203 
    204 /* CURLMPOPT_SOCKETFUNCTION */
    205 /* libcurl wants us to tell it when sock is ready to be processed */
    206 static void
    207 multi_sock_cb( CURL            * easy UNUSED,
    208                curl_socket_t     sock,
    209                int               action,
    210                void            * vweb,
    211                void            * assigndata )
    212 {
    213     tr_web * web = vweb;
    214     struct event * ev = assigndata;
    215 
    216     if( action == CURL_POLL_REMOVE ) {
    217         if( ev ) {
    218             dbgmsg( "deleting libevent socket polling" );
    219             event_del( ev );
    220             tr_free( ev );
    221             curl_multi_assign( web->cm, sock, NULL );
    222         }
     198    assert( web->running );
     199
     200    pump( web );
     201
     202    evtimer_del( &web->timer );
     203
     204    web->running = web->remain > 0;
     205
     206    if( web->running ) {
     207        struct timeval tv = tr_timevalMsec( PULSE_MSEC );
     208        evtimer_add( &web->timer, &tv );
     209    } else if( web->dying ) {
     210        webDestroy( web );
    223211    } else {
    224         int kind;
    225         if( ev ) {
    226             event_del( ev );
    227         } else {
    228             ev = tr_new0( struct event, 1 );
    229             curl_multi_assign( web->cm, sock, ev );
    230         }
    231         kind = EV_PERSIST;
    232         if( action & CURL_POLL_IN ) kind |= EV_READ;
    233         if( action & CURL_POLL_OUT ) kind |= EV_WRITE;
    234         event_set( ev, sock, kind, ev_sock_cb, web );
    235         event_add( ev, NULL );
    236     }
    237 }
    238 
    239 /* libevent says that timeout_ms have passed, so tell libcurl */
    240 static void
    241 event_timer_cb( int socket UNUSED, short action UNUSED, void * vweb )
    242 {
    243     int unused;
    244     CURLMcode rc;
    245     tr_web * web = vweb;
    246 
    247     do {
    248         rc = curl_multi_socket( web->cm, CURL_SOCKET_TIMEOUT, &unused );
    249     } while( rc == CURLM_CALL_MULTI_PERFORM );
    250     if ( rc == CURLM_OK  )
    251         processCompletedTasks( web );
    252     else
    253         tr_err( "%s", curl_multi_strerror(rc) );
    254 }
    255 
    256 /* CURLMPOPT_TIMERFUNCTION */
    257 static void
    258 multi_timer_cb( CURLM *multi UNUSED, long timeout_ms, void * vweb )
    259 {
    260     tr_web * web = vweb;
    261     struct timeval tv = tr_timevalMsec( timeout_ms );
    262     evtimer_add( &web->timer, &tv );
    263 }
    264 
    265 #else
    266 
    267 static void
    268 pulse( int socket UNUSED, short action UNUSED, void * vweb )
    269 {
    270     tr_web * web = vweb;
    271     struct timeval tv = tr_timevalMsec( PULSE_MSEC );
    272 
    273     pump( web );
    274 
    275     evtimer_del( &web->timer );
    276     evtimer_add( &web->timer, &tv );
    277 }
    278 
    279 #endif
     212        dbgmsg( "stopping web timer" );
     213    }
     214}
    280215
    281216tr_web*
    282217tr_webInit( tr_session * session )
    283218{
    284 #ifndef USE_CURL_MULTI_SOCKET
    285     struct timeval tv = tr_timevalMsec( PULSE_MSEC );
    286 #endif
    287219    static int curlInited = FALSE;
    288220    tr_web * web;
     
    301233    web->session = session;
    302234
    303 #ifdef USE_CURL_MULTI_SOCKET
    304     evtimer_set( &web->timer, event_timer_cb, web );
    305     curl_multi_setopt( web->cm, CURLMOPT_SOCKETDATA, web );
    306     curl_multi_setopt( web->cm, CURLMOPT_SOCKETFUNCTION, multi_sock_cb );
    307     curl_multi_setopt( web->cm, CURLMOPT_TIMERDATA, web );
    308     curl_multi_setopt( web->cm, CURLMOPT_TIMERFUNCTION, multi_timer_cb );
    309 #else
    310235    evtimer_set( &web->timer, pulse, web );
    311     evtimer_add( &web->timer, &tv );
    312 #endif
    313236#if CURL_CHECK_VERSION(7,16,3)
    314237    curl_multi_setopt( web->cm, CURLMOPT_MAXCONNECTS, 10 );
     
    320243
    321244void
    322 tr_webClose( tr_web ** web )
    323 {
    324     dbgmsg( "deleting web->timer" );
    325     evtimer_del( &(*web)->timer );
    326     curl_multi_cleanup( (*web)->cm );
    327     tr_free( *web );
    328     *web = NULL;
     245tr_webClose( tr_web ** web_in )
     246{
     247    tr_web * web = *web_in;
     248    *web_in = NULL;
     249
     250    if( !web->running )
     251        webDestroy( web );
     252    else
     253        web->dying = 1;
    329254}
    330255
Note: See TracChangeset for help on using the changeset viewer.