mirror of
https://github.com/transmission/transmission.git
synced 2025-12-24 20:35:36 +00:00
(trunk) fix some of the crash-on-shutdown issues.
This commit is contained in:
@@ -66,6 +66,7 @@ struct tr_thread_s
|
||||
thread_id thread;
|
||||
#elif defined(WIN32)
|
||||
HANDLE thread;
|
||||
unsigned int thread_id;
|
||||
#else
|
||||
pthread_t thread;
|
||||
#endif
|
||||
@@ -116,7 +117,7 @@ tr_threadNew( void (*func)(void *),
|
||||
t->thread = spawn_thread( (void*)ThreadFunc, name, B_NORMAL_PRIORITY, t );
|
||||
resume_thread( t->thread );
|
||||
#elif defined(WIN32)
|
||||
t->thread = (HANDLE) _beginthreadex( NULL, 0, &ThreadFunc, t, 0, NULL );
|
||||
t->thread = (HANDLE) _beginthreadex( NULL, 0, &ThreadFunc, t, 0, &t->thread_id );
|
||||
#else
|
||||
pthread_create( &t->thread, NULL, (void * (*) (void *)) ThreadFunc, t );
|
||||
#endif
|
||||
@@ -124,6 +125,20 @@ tr_threadNew( void (*func)(void *),
|
||||
return t;
|
||||
}
|
||||
|
||||
int
|
||||
tr_amInThread ( const tr_thread_t * t )
|
||||
{
|
||||
int ret;
|
||||
#ifdef __BEOS__
|
||||
ret = find_thread(NULL) == t->thread;
|
||||
#elif defined(WIN32)
|
||||
ret = GetCurrentThreadId() == t->thread_id;
|
||||
#else
|
||||
ret = pthread_equal( t->thread, pthread_self( ) );
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
tr_threadJoin( tr_thread_t * t )
|
||||
{
|
||||
@@ -348,7 +363,7 @@ struct tr_cond_s
|
||||
thread_id threads[BEOS_MAX_THREADS];
|
||||
int start, end;
|
||||
#elif defined(WIN32)
|
||||
tr_list_t * events;
|
||||
tr_list * events;
|
||||
tr_lock_t * lock;
|
||||
#else
|
||||
pthread_cond_t cond;
|
||||
@@ -491,7 +506,7 @@ tr_condBroadcast( tr_cond_t * c )
|
||||
|
||||
#elif defined(WIN32)
|
||||
|
||||
tr_list_t * l;
|
||||
tr_list * l;
|
||||
tr_lockLock( c->lock );
|
||||
for( l=c->events; l!=NULL; l=l->next )
|
||||
SetEvent( (HANDLE)l->data );
|
||||
|
||||
@@ -34,6 +34,7 @@ const char * tr_getTorrentsDirectory( void );
|
||||
|
||||
tr_thread_t* tr_threadNew ( void (*func)(void *), void * arg, const char * name );
|
||||
void tr_threadJoin ( tr_thread_t * );
|
||||
int tr_amInThread ( const tr_thread_t * );
|
||||
|
||||
tr_lock_t * tr_lockNew ( void );
|
||||
void tr_lockFree ( tr_lock_t * );
|
||||
|
||||
@@ -35,33 +35,15 @@ struct timer_node
|
||||
void * user_data;
|
||||
tr_data_free_func * free_func;
|
||||
struct timeval tv;
|
||||
int refcount;
|
||||
uint8_t doFree;
|
||||
};
|
||||
|
||||
static void
|
||||
unref( struct timer_node * node, int count )
|
||||
{
|
||||
assert( node != NULL );
|
||||
assert( node->refcount > 0 );
|
||||
|
||||
node->refcount -= count;
|
||||
if( node->refcount > 0 )
|
||||
return;
|
||||
|
||||
if( node->free_func != NULL )
|
||||
(node->free_func)( node->user_data );
|
||||
tr_event_del( node->handle, node->event );
|
||||
tr_free( node );
|
||||
}
|
||||
|
||||
void
|
||||
tr_timerFree( struct timer_node ** node )
|
||||
{
|
||||
assert( node != NULL );
|
||||
|
||||
if( *node )
|
||||
{
|
||||
unref( *node, 1 );
|
||||
(*node)->doFree = 1;
|
||||
*node = NULL;
|
||||
}
|
||||
}
|
||||
@@ -70,15 +52,15 @@ static void
|
||||
timerCB( int fd UNUSED, short event UNUSED, void * arg )
|
||||
{
|
||||
struct timer_node * node = (struct timer_node *) arg;
|
||||
int val;
|
||||
|
||||
++node->refcount;
|
||||
val = (node->func)(node->user_data);
|
||||
if( !val )
|
||||
unref( node, 2 );
|
||||
else {
|
||||
timeout_add( node->event, &node->tv );
|
||||
unref( node, 1 );
|
||||
if( !node->doFree )
|
||||
node->doFree = !(node->func)(node->user_data);
|
||||
|
||||
if( node->doFree ) {
|
||||
if( node->free_func != NULL )
|
||||
(node->free_func)( node->user_data );
|
||||
tr_event_del( node->handle, node->event );
|
||||
tr_free( node );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +83,7 @@ tr_timerNew( tr_handle_t * handle,
|
||||
node->func = func;
|
||||
node->user_data = user_data;
|
||||
node->free_func = free_func;
|
||||
node->refcount = 1;
|
||||
node->doFree = 0;
|
||||
node->tv = timevalMsec ( timeout_milliseconds );
|
||||
timeout_set( node->event, timerCB, node );
|
||||
tr_event_add( handle, node->event, &node->tv );
|
||||
|
||||
@@ -25,11 +25,11 @@ typedef struct timer_node * tr_timer_tag;
|
||||
* zero or from a client call to tr_timerFree). This is useful
|
||||
* if user_data has resources that need to be freed.
|
||||
*/
|
||||
tr_timer_tag tr_timerNew( struct tr_handle_s * handle,
|
||||
int timer_func( void * user_data ),
|
||||
void * user_data,
|
||||
void free_func( void * user_data ),
|
||||
int timeout_milliseconds );
|
||||
tr_timer_tag tr_timerNew( struct tr_handle_s * handle,
|
||||
int timer_func( void * user_data ),
|
||||
void * user_data,
|
||||
void free_func( void * user_data ),
|
||||
int timeout_milliseconds );
|
||||
|
||||
/**
|
||||
* Frees a timer and sets its tag to NULL.
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/queue.h> /* for evhttp */
|
||||
#include <sys/types.h> /* for evhttp */
|
||||
@@ -48,6 +49,7 @@ typedef struct tr_event_handle_s
|
||||
int fds[2];
|
||||
tr_lock_t * lock;
|
||||
tr_handle_t * h;
|
||||
tr_thread_t * thread;
|
||||
struct event_base * base;
|
||||
struct event pipeEvent;
|
||||
}
|
||||
@@ -70,6 +72,10 @@ readFromPipe( int fd, short eventType UNUSED, void * unused UNUSED )
|
||||
struct evhttp_request * req;
|
||||
enum evhttp_cmd_type type;
|
||||
char * uri;
|
||||
char * buf;
|
||||
size_t buflen;
|
||||
struct bufferevent * bufev;
|
||||
short mode;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf( stderr, "reading...reads: [%d] writes: [%d]\n", ++reads, writes );
|
||||
@@ -88,7 +94,6 @@ readFromPipe( int fd, short eventType UNUSED, void * unused UNUSED )
|
||||
{
|
||||
case 'd': /* event_del */
|
||||
read( fd, &event, sizeof(struct event*) );
|
||||
tr_dbg( "read del event from pipe: event is %p", event );
|
||||
event_del( event );
|
||||
tr_free( event );
|
||||
break;
|
||||
@@ -96,7 +101,6 @@ readFromPipe( int fd, short eventType UNUSED, void * unused UNUSED )
|
||||
case 'e': /* event_add */
|
||||
read( fd, &event, sizeof(struct event*) );
|
||||
read( fd, &interval, sizeof(struct timeval) );
|
||||
tr_dbg( "read event from pipe: event.ev_arg is %p", event->ev_arg );
|
||||
event_add( event, &interval );
|
||||
break;
|
||||
|
||||
@@ -105,11 +109,29 @@ readFromPipe( int fd, short eventType UNUSED, void * unused UNUSED )
|
||||
read( fd, &req, sizeof(struct evhttp_request*) );
|
||||
read( fd, &type, sizeof(enum evhttp_cmd_type) );
|
||||
read( fd, &uri, sizeof(char*) );
|
||||
tr_dbg( "read http req from pipe: req.cb_arg is %p", req->cb_arg );
|
||||
evhttp_make_request( evcon, req, type, uri );
|
||||
tr_free( uri );
|
||||
break;
|
||||
|
||||
case 'm': /* set bufferevent mode */
|
||||
read( fd, &bufev, sizeof(struct evhttp_request*) );
|
||||
mode = 0;
|
||||
read( fd, &mode, sizeof(short) );
|
||||
bufferevent_enable( bufev, mode );
|
||||
mode = 0;
|
||||
read( fd, &mode, sizeof(short) );
|
||||
bufferevent_disable( bufev, mode );
|
||||
fprintf( stderr, "after enable/disable, the mode is %hd\n", bufev->enabled );
|
||||
break;
|
||||
|
||||
case 'w': /* bufferevent_write */
|
||||
read( fd, &bufev, sizeof(struct bufferevent*) );
|
||||
read( fd, &buf, sizeof(char*) );
|
||||
read( fd, &buflen, sizeof(size_t) );
|
||||
bufferevent_write( bufev, buf, buflen );
|
||||
tr_free( buf );
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( 0 && "unhandled event pipe condition!" );
|
||||
}
|
||||
@@ -165,7 +187,7 @@ tr_eventInit( tr_handle_t * handle )
|
||||
pipe( eh->fds );
|
||||
eh->h = handle;
|
||||
handle->events = eh;
|
||||
tr_threadNew( libeventThreadFunc, eh, "libeventThreadFunc" );
|
||||
eh->thread = tr_threadNew( libeventThreadFunc, eh, "libeventThreadFunc" );
|
||||
}
|
||||
|
||||
void
|
||||
@@ -181,37 +203,46 @@ tr_event_add( tr_handle_t * handle,
|
||||
struct event * event,
|
||||
struct timeval * interval )
|
||||
{
|
||||
const char ch = 'e';
|
||||
int fd = handle->events->fds[1];
|
||||
tr_lock_t * lock = handle->events->lock;
|
||||
if( tr_amInThread( handle->events->thread ) )
|
||||
{
|
||||
event_add( event, interval );
|
||||
}
|
||||
else
|
||||
{
|
||||
const char ch = 'e';
|
||||
int fd = handle->events->fds[1];
|
||||
tr_lock_t * lock = handle->events->lock;
|
||||
|
||||
tr_lockLock( lock );
|
||||
tr_dbg( "writing event to pipe: event.ev_arg is %p", event->ev_arg );
|
||||
#ifdef DEBUG
|
||||
fprintf( stderr, "reads: [%d] writes: [%d]\n", reads, ++writes );
|
||||
#endif
|
||||
write( fd, &ch, 1 );
|
||||
write( fd, &event, sizeof(struct event*) );
|
||||
write( fd, interval, sizeof(struct timeval) );
|
||||
tr_lockUnlock( lock );
|
||||
tr_lockLock( lock );
|
||||
tr_dbg( "writing event to pipe: event.ev_arg is %p", event->ev_arg );
|
||||
write( fd, &ch, 1 );
|
||||
write( fd, &event, sizeof(struct event*) );
|
||||
write( fd, interval, sizeof(struct timeval) );
|
||||
tr_lockUnlock( lock );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tr_event_del( tr_handle_t * handle,
|
||||
struct event * event )
|
||||
{
|
||||
const char ch = 'd';
|
||||
int fd = handle->events->fds[1];
|
||||
tr_lock_t * lock = handle->events->lock;
|
||||
if( tr_amInThread( handle->events->thread ) )
|
||||
{
|
||||
event_del( event );
|
||||
tr_free( event );
|
||||
}
|
||||
else
|
||||
{
|
||||
const char ch = 'd';
|
||||
int fd = handle->events->fds[1];
|
||||
tr_lock_t * lock = handle->events->lock;
|
||||
|
||||
tr_lockLock( lock );
|
||||
tr_dbg( "writing event to pipe: del event %p", event );
|
||||
#ifdef DEBUG
|
||||
fprintf( stderr, "reads: [%d] writes: [%d]\n", reads, ++writes );
|
||||
#endif
|
||||
write( fd, &ch, 1 );
|
||||
write( fd, &event, sizeof(struct event*) );
|
||||
tr_lockUnlock( lock );
|
||||
tr_lockLock( lock );
|
||||
tr_dbg( "writing event to pipe: del event %p", event );
|
||||
write( fd, &ch, 1 );
|
||||
write( fd, &event, sizeof(struct event*) );
|
||||
tr_lockUnlock( lock );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -221,19 +252,77 @@ tr_evhttp_make_request (tr_handle_t * handle,
|
||||
enum evhttp_cmd_type type,
|
||||
char * uri)
|
||||
{
|
||||
const char ch = 'h';
|
||||
int fd = handle->events->fds[1];
|
||||
tr_lock_t * lock = handle->events->lock;
|
||||
if( tr_amInThread( handle->events->thread ) )
|
||||
{
|
||||
evhttp_make_request( evcon, req, type, uri );
|
||||
tr_free( uri );
|
||||
}
|
||||
else
|
||||
{
|
||||
const char ch = 'h';
|
||||
int fd = handle->events->fds[1];
|
||||
tr_lock_t * lock = handle->events->lock;
|
||||
|
||||
tr_lockLock( lock );
|
||||
tr_dbg( "writing HTTP req to pipe: req.cb_arg is %p", req->cb_arg );
|
||||
#ifdef DEBUG
|
||||
fprintf( stderr, "reads: [%d] writes: [%d]\n", reads, ++writes );
|
||||
#endif
|
||||
write( fd, &ch, 1 );
|
||||
write( fd, &evcon, sizeof(struct evhttp_connection*) );
|
||||
write( fd, &req, sizeof(struct evhttp_request*) );
|
||||
write( fd, &type, sizeof(enum evhttp_cmd_type) );
|
||||
write( fd, &uri, sizeof(char*) );
|
||||
tr_lockUnlock( lock );
|
||||
tr_lockLock( lock );
|
||||
tr_dbg( "writing HTTP req to pipe: req.cb_arg is %p", req->cb_arg );
|
||||
write( fd, &ch, 1 );
|
||||
write( fd, &evcon, sizeof(struct evhttp_connection*) );
|
||||
write( fd, &req, sizeof(struct evhttp_request*) );
|
||||
write( fd, &type, sizeof(enum evhttp_cmd_type) );
|
||||
write( fd, &uri, sizeof(char*) );
|
||||
tr_lockUnlock( lock );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tr_bufferevent_write( tr_handle_t * handle,
|
||||
struct bufferevent * bufev,
|
||||
const void * buf,
|
||||
size_t buflen )
|
||||
{
|
||||
if( tr_amInThread( handle->events->thread ) )
|
||||
{
|
||||
bufferevent_write( bufev, (void*)buf, buflen );
|
||||
}
|
||||
else
|
||||
{
|
||||
const char ch = 'w';
|
||||
int fd = handle->events->fds[1];
|
||||
tr_lock_t * lock = handle->events->lock;
|
||||
char * local = tr_strndup( buf, buflen );
|
||||
|
||||
tr_lockLock( lock );
|
||||
tr_dbg( "writing bufferevent_write pipe" );
|
||||
write( fd, &ch, 1 );
|
||||
write( fd, &bufev, sizeof(struct bufferevent*) );
|
||||
write( fd, &local, sizeof(char*) );
|
||||
write( fd, &buflen, sizeof(size_t) );
|
||||
tr_lockUnlock( lock );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tr_setBufferEventMode( struct tr_handle_s * handle,
|
||||
struct bufferevent * bufev,
|
||||
short mode_enable,
|
||||
short mode_disable )
|
||||
{
|
||||
if( tr_amInThread( handle->events->thread ) )
|
||||
{
|
||||
bufferevent_enable( bufev, mode_enable );
|
||||
bufferevent_disable( bufev, mode_disable );
|
||||
}
|
||||
else
|
||||
{
|
||||
const char ch = 'm';
|
||||
int fd = handle->events->fds[1];
|
||||
tr_lock_t * lock = handle->events->lock;
|
||||
|
||||
tr_lockLock( lock );
|
||||
write( fd, &ch, 1 );
|
||||
write( fd, &bufev, sizeof(struct bufferevent*) );
|
||||
write( fd, &mode_enable, sizeof(short) );
|
||||
write( fd, &mode_disable, sizeof(short) );
|
||||
tr_lockUnlock( lock );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
#ifndef TR_EVENT_H
|
||||
|
||||
#include <stddef.h> /* for size_t */
|
||||
|
||||
/**
|
||||
**/
|
||||
|
||||
@@ -26,18 +28,29 @@ struct event;
|
||||
enum evhttp_cmd_type;
|
||||
struct evhttp_request;
|
||||
struct evhttp_connection;
|
||||
struct bufferevent;
|
||||
|
||||
void tr_event_add( struct tr_handle_s * tr_handle,
|
||||
struct event * event,
|
||||
struct timeval * interval );
|
||||
struct event * event,
|
||||
struct timeval * interval );
|
||||
|
||||
void tr_event_del( struct tr_handle_s * tr_handle,
|
||||
struct event * event );
|
||||
struct event * event );
|
||||
|
||||
void tr_evhttp_make_request (struct tr_handle_s * tr_handle,
|
||||
void tr_evhttp_make_request (struct tr_handle_s * tr_handle,
|
||||
struct evhttp_connection * evcon,
|
||||
struct evhttp_request * req,
|
||||
enum evhttp_cmd_type type,
|
||||
char * uri);
|
||||
|
||||
void tr_bufferevent_write( struct tr_handle_s * tr_handle,
|
||||
struct bufferevent * bufferEvent,
|
||||
const void * buf,
|
||||
size_t buflen );
|
||||
|
||||
void tr_setBufferEventMode( struct tr_handle_s * tr_handle,
|
||||
struct bufferevent * bufferEvent,
|
||||
short mode_enable,
|
||||
short mode_disable );
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user