diff options
author | Reinhard Nißl <rnissl@gmx.de> | 2007-04-12 22:14:06 +0200 |
---|---|---|
committer | Reinhard Nißl <rnissl@gmx.de> | 2007-04-12 22:14:06 +0200 |
commit | b4304f243c6006eec3ca4b4ce2b19cfca703861a (patch) | |
tree | e6b00eb9566334c35b6f1f5285c1cae675c7b821 /src | |
parent | c552e457732c3c7b84b66ed8548713be52561487 (diff) | |
download | xine-lib-b4304f243c6006eec3ca4b4ce2b19cfca703861a.tar.gz xine-lib-b4304f243c6006eec3ca4b4ce2b19cfca703861a.tar.bz2 |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/xine-engine/xine.c | 49 | ||||
-rw-r--r-- | src/xine-engine/xine_internal.h | 9 |
2 files changed, 48 insertions, 10 deletions
diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index f49a988c9..612bf8dcc 100644 --- a/src/xine-engine/xine.c +++ b/src/xine-engine/xine.c @@ -127,23 +127,42 @@ void _x_extra_info_merge( extra_info_t *dst, extra_info_t *src ) { } } -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) - pthread_cond_wait(&this->issued, &this->lock); + 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); + } this->tickets_granted++; if (irrevocable) this->irrevocable_tickets++; pthread_mutex_unlock(&this->lock); + return 1; } -static void ticket_release(xine_ticket_t *this, int irrevocable) { +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,12 +172,20 @@ static void ticket_release(xine_ticket_t *this, int irrevocable) { 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) { pthread_mutex_lock(&this->lock); @@ -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 --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h index 30899a4b3..da6f88a7f 100644 --- a/src/xine-engine/xine_internal.h +++ b/src/xine-engine/xine_internal.h @@ -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; |