From 4447c70039ba1a3104bf229628699f33b8608973 Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 02 Dec 2002 10:25:36 +0000 Subject: - put a thread pipe between the xine callback handler and the receiver on qt side, to avoid problems like repaints from within a non-gui thread --- (limited to 'noncore/multimedia/opieplayer2/threadutil.cpp') diff --git a/noncore/multimedia/opieplayer2/threadutil.cpp b/noncore/multimedia/opieplayer2/threadutil.cpp new file mode 100644 index 0000000..63863b4 --- a/dev/null +++ b/noncore/multimedia/opieplayer2/threadutil.cpp @@ -0,0 +1,284 @@ +/* This file is part of the KDE project + Copyright (C) 1999 Simon Hausmann + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "threadutil.h" + +#include + +#include +#include +#include + +using namespace ThreadUtil; + +struct Mutex::Data +{ + Data() + { + pthread_mutex_init( &mutex, 0 ); + } + ~Data() + { + pthread_mutex_destroy( &mutex ); + } + + pthread_mutex_t mutex; +}; + +Mutex::Mutex() + : d( new Data ) +{ +} + +Mutex::~Mutex() +{ + delete d; +} + +void Mutex::lock() +{ + pthread_mutex_lock( &d->mutex ); +} + +void Mutex::unlock() +{ + pthread_mutex_unlock( &d->mutex ); +} + +bool Mutex::tryLock() +{ + return pthread_mutex_trylock( &d->mutex ) == 0; +} + +bool Mutex::isLocked() +{ + if ( !tryLock() ) + return true; + + unlock(); + return false; +} + +struct WaitCondition::Data +{ + Data() + { + int result = pthread_cond_init( &waitCondition, 0 ); + assert( result == 0 ); + } + ~Data() + { + pthread_cond_destroy( &waitCondition ); + } + + pthread_cond_t waitCondition; +}; + +WaitCondition::WaitCondition() + : d( new Data ) +{ +} + +WaitCondition::~WaitCondition() +{ + delete d; +} + +bool WaitCondition::wait() +{ + Mutex m; + m.lock(); + return wait( m ); +} + +bool WaitCondition::wait( Mutex &mutex ) +{ + return pthread_cond_wait( &d->waitCondition, &mutex.d->mutex ); +} + +void WaitCondition::wakeOne() +{ + pthread_cond_signal( &d->waitCondition ); +} + +void WaitCondition::wakeAll() +{ + pthread_cond_broadcast( &d->waitCondition ); +} + +OnewayNotifier::OnewayNotifier() +{ + int fds[ 2 ]; + pipe( fds ); + m_readFd = fds[ 0 ]; + m_writeFd = fds[ 1 ]; + + m_notifier = new QSocketNotifier( m_readFd, QSocketNotifier::Read ); + connect( m_notifier, SIGNAL( activated( int ) ), + this, SLOT( wakeUp() ) ); +} + +OnewayNotifier::~OnewayNotifier() +{ + delete m_notifier; + + ::close( m_readFd ); + ::close( m_writeFd ); +} + +void OnewayNotifier::notify() +{ + const char c = 42; + ::write( m_writeFd, &c, 1 ); +} + +void OnewayNotifier::wakeUp() +{ + char c = 0; + + if ( ::read( m_readFd, &c, 1 ) != 1 ) + return; + + emit awake(); +} + +ChannelMessage::ChannelMessage( int type ) + : m_type( type ), m_isCall( false ), m_replied( false ), + m_inEventHandler( false ) +{ +} + +ChannelMessage::~ChannelMessage() +{ + if ( m_guard.isLocked() ) + m_guard.unlock(); +} + +void ChannelMessage::reply() +{ + if ( !m_isCall ) + { + qDebug( "ChannelMessage::reply() - can't reply oneway message!" ); + return; + } + + if ( m_inEventHandler ) + { + m_replied = true; + return; + } + + m_condition.wakeOne(); + m_guard.unlock(); +} + +struct Channel::Private +{ + Private() + { + ownerThread = pthread_self(); + } + + pthread_t ownerThread; +}; + +Channel::Channel( QObject *parent, const char *name ) + : QObject( parent, name ), d( new Private ) +{ + connect( &m_notifier, SIGNAL( awake() ), + this, SLOT( deliver() ) ); +} + +Channel::~Channel() +{ + delete d; +} + +void Channel::send( ChannelMessage *message, SendType type ) +{ + if ( type == WaitForReply ) + { + message->m_guard.lock(); + message->m_isCall = true; + } + + m_pendingMessagesGuard.lock(); + m_pendingMessages << MsgEnvelope( type, message ); + m_pendingMessagesGuard.unlock(); + + if ( d->ownerThread == pthread_self() ) { + assert( type != WaitForReply ); + + deliver(); + } + else + m_notifier.notify(); + //QThread::postEvent( this, new QCustomEvent( QEvent::User, envelope ) ); + + if ( type == WaitForReply ) + { + message->m_condition.wait( message->m_guard ); + message->m_guard.unlock(); + } +} + +void Channel::deliver() +{ + AutoLock lock( m_pendingMessagesGuard ); + + while ( !m_pendingMessages.isEmpty() ) { + MsgEnvelope envelope = m_pendingMessages.first(); + + m_pendingMessages.remove( m_pendingMessages.begin() ); + + m_pendingMessagesGuard.unlock(); + deliverOne( envelope ); + m_pendingMessagesGuard.lock(); + } +} + +void Channel::deliverOne( const MsgEnvelope &envelope ) +{ + ChannelMessage *msg = envelope.msg; + + assert( msg ); + + if ( envelope.type == WaitForReply ) + { + msg->m_guard.lock(); + msg->m_inEventHandler = true; + } + + receiveMessage( msg, envelope.type ); + + if ( envelope.type == WaitForReply ) + { + msg->m_inEventHandler = false; + if ( msg->m_replied ) + { + msg->m_condition.wakeOne(); + // this is a bit tricky. we unlock only when we reply. + // reply() does an unlock as well. + msg->m_guard.unlock(); + } + } +} + +/* vim: et sw=4 ts=4 + */ -- cgit v0.9.0.2