From: <rn...@gm...> - 2007-04-12 23:33:23
|
# HG changeset patch # User Reinhard Nißl <rn...@gm...> # Date 1176408846 -7200 # Node ID 03479690e8d535e2a1776307fd81f4824748fbdf # Parent 26f54d63fa602a6d2dc5ed3243745df8b4e1f3dd Extend ticket system for nonblocking ticket acquiries. The current code has a race condition which can block arbitrary threads that call for example xine_get_current_frame() until the stream gets unpaused again. This can happen when the internal ticket acquiration collides with a ticket revokation for example when another thread is going to pause the stream. There are a few situations where a port ticket needs to be acquired for calling a port function but where it is absolutely undesireable to get blocked for an undetermined period of time. Therefore the ticket system should be extended by nonblocking functions which allow ticket acquiration even when a ticket revokation is in progress. And in the case where blocking is not avoidable, it should simply be indicated that no ticket was acquired. The caller can then choose to repeat the call at a later point in time. diff -r 03479690e8d535e2a1776307fd81f4824748fbdf -r 26f54d63fa602a6d2dc5ed3243745df8b4e1f3dd src/xine-engine/xine.c --- a/src/xine-engine/xine.c Thu Apr 12 22:14:06 2007 +0200 +++ b/src/xine-engine/xine.c Mon Apr 09 19:57:25 2007 +0200 @@ -127,23 +127,42 @@ void _x_extra_info_merge( extra_info_t * } } -static void ticket_acquire(xine_ticket_t *this, int irrevocable) { +static int ticket_acquire_internal(xine_ticket_t *this, int irrevocable, int nonblocking) { + int must_wait = 0; pthread_mutex_lock(&this->lock); if (this->ticket_revoked && !this->irrevocable_tickets) + must_wait = !nonblocking; + else if (this->atomic_revoke && !pthread_equal(this->atomic_revoker_thread, pthread_self())) + must_wait = 1; + + if (must_wait) { + if (nonblocking) { + pthread_mutex_unlock(&this->lock); + return 0; + } + pthread_cond_wait(&this->issued, &this->lock); - else if (this->atomic_revoke && !pthread_equal(this->atomic_revoker_thread, pthread_self())) - pthread_cond_wait(&this->issued, &this->lock); + } this->tickets_granted++; if (irrevocable) this->irrevocable_tickets++; pthread_mutex_unlock(&this->lock); -} - -static void ticket_release(xine_ticket_t *this, int irrevocable) { + return 1; +} + +static int ticket_acquire_nonblocking(xine_ticket_t *this, int irrevocable) { + return ticket_acquire_internal(this, irrevocable, 1); +} + +static void ticket_acquire(xine_ticket_t *this, int irrevocable) { + ticket_acquire_internal(this, irrevocable, 0); +} + +static void ticket_release_internal(xine_ticket_t *this, int irrevocable, int nonblocking) { pthread_mutex_lock(&this->lock); @@ -153,10 +172,18 @@ static void ticket_release(xine_ticket_t if (this->ticket_revoked && !this->tickets_granted) pthread_cond_broadcast(&this->revoked); - if (this->ticket_revoked && !this->irrevocable_tickets) + if (this->ticket_revoked && !this->irrevocable_tickets && !nonblocking) pthread_cond_wait(&this->issued, &this->lock); pthread_mutex_unlock(&this->lock); +} + +static void ticket_release_nonblocking(xine_ticket_t *this, int irrevocable) { + ticket_release_internal(this, irrevocable, 1); +} + +static void ticket_release(xine_ticket_t *this, int irrevocable) { + ticket_release_internal(this, irrevocable, 0); } static void ticket_renew(xine_ticket_t *this, int irrevocable) { @@ -227,12 +254,14 @@ static xine_ticket_t *ticket_init(void) port_ticket = (xine_ticket_t *) xine_xmalloc(sizeof(xine_ticket_t)); - port_ticket->acquire = ticket_acquire; - port_ticket->release = ticket_release; - port_ticket->renew = ticket_renew; - port_ticket->issue = ticket_issue; - port_ticket->revoke = ticket_revoke; - port_ticket->dispose = ticket_dispose; + port_ticket->acquire_nonblocking = ticket_acquire_nonblocking; + port_ticket->acquire = ticket_acquire; + port_ticket->release_nonblocking = ticket_release_nonblocking; + port_ticket->release = ticket_release; + port_ticket->renew = ticket_renew; + port_ticket->issue = ticket_issue; + port_ticket->revoke = ticket_revoke; + port_ticket->dispose = ticket_dispose; pthread_mutex_init(&port_ticket->lock, NULL); pthread_mutex_init(&port_ticket->revoke_lock, NULL); diff -r 03479690e8d535e2a1776307fd81f4824748fbdf -r 26f54d63fa602a6d2dc5ed3243745df8b4e1f3dd src/xine-engine/xine_internal.h --- a/src/xine-engine/xine_internal.h Thu Apr 12 22:14:06 2007 +0200 +++ b/src/xine-engine/xine_internal.h Mon Apr 09 19:57:25 2007 +0200 @@ -159,6 +159,15 @@ struct xine_ticket_s { * revocation or by other threads acquiring tickets */ void (*revoke)(xine_ticket_t *self, int atomic); + /* behaves like acquire() but doesn't block the calling thread; when + * the thread would have been blocked, 0 is returned otherwise 1 + * this function acquires a ticket even if ticket revocation is active */ + int (*acquire_nonblocking)(xine_ticket_t *self, int irrevocable); + + /* behaves like release() but doesn't block the calling thread; should + * be used in combination with acquire_nonblocking() */ + void (*release_nonblocking)(xine_ticket_t *self, int irrevocable); + void (*dispose)(xine_ticket_t *self); pthread_mutex_t lock; |