blob: 089a9bd19988694599845136a618668ba7c67bd2 [file] [log] [blame]
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Author: morlovich@google.com (Maksim Orlovich)
//
// This contains classes that abstract away creation of threads and
// synchronization primitives.
// - ThreadSystem (base class): acts as a factory for mutexes compatible
// with some runtime environment and must be passed to Thread ctor to use its
// threading abilities.
// - ThreadImpl: abstract interface used to communicate with threading
// backends by Thread instances.
#ifndef PAGESPEED_KERNEL_BASE_THREAD_SYSTEM_H_
#define PAGESPEED_KERNEL_BASE_THREAD_SYSTEM_H_
#include "pagespeed/kernel/base/abstract_mutex.h"
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/thread_annotations.h"
namespace net_instaweb {
class Timer;
// Subclasses of this represent threading support under given environment,
// and help create various primitives for it.
class ThreadSystem {
public:
class Condvar;
class Thread;
class ThreadImpl;
class LOCKABLE CondvarCapableMutex : public AbstractMutex {
public:
CondvarCapableMutex() { }
virtual ~CondvarCapableMutex();
// Creates a new condition variable associated with 'this' mutex.
virtual Condvar* NewCondvar() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(CondvarCapableMutex);
};
// Interface for a Mutex with ReaderLocks(). It is possible for multiple
// Readers to simultaneously hold an RWLock. A reader cannot hold the
// lock at the same time as a Writer, nor can two Writers hold the lock.
class LOCKABLE RWLock : public AbstractMutex {
public:
RWLock() {}
virtual ~RWLock();
// ReaderLock/Unlock are different from normal locks. Reader locks are
// shared while normal locks are exclusive. Normal lock cannot happen when
// reader has a lock.
// Try to acquire a read share of this lock without blocking.
virtual bool ReaderTryLock() SHARED_TRYLOCK_FUNCTION(true) = 0;
// Block until this Mutex is free, or shared, then acquire a share of it.
virtual void ReaderLock() SHARED_LOCK_FUNCTION() = 0;
// Release a read share of this Mutex.
virtual void ReaderUnlock() UNLOCK_FUNCTION() = 0;
// Optionally checks that reader lock is held (for invariant checking
// purposes). Default implementation does no checking.
virtual void DCheckReaderLocked();
private:
DISALLOW_COPY_AND_ASSIGN(RWLock);
};
// Scoped reader-lock for using RWLock*. Facilitates grabbing a
// reader-lock on entry to a scope, and releasing it on exit.
// Similar to ScopedMutex found in AbstractMutex, except that
// multiple ScopedReaders can be simultaneously instantiated on
// the same RWLock*.
class SCOPED_LOCKABLE ScopedReader {
public:
explicit ScopedReader(RWLock* lock) SHARED_LOCK_FUNCTION(lock)
: lock_(lock) {
lock_->ReaderLock();
}
void Release() UNLOCK_FUNCTION() {
// We allow Release called explicitly, before the ScopedReader goes
// out of scope and is destructed, calling Release again.
if (lock_ != NULL) {
lock_->ReaderUnlock();
lock_ = NULL;
}
}
~ScopedReader() UNLOCK_FUNCTION() { Release(); }
private:
RWLock* lock_;
DISALLOW_COPY_AND_ASSIGN(ScopedReader);
};
// Encapsulates a thread ID, whose type is dependent on the thread system
// implementation, and may be non-integral. E.g, see
// http://linux.die.net/man/3/pthread_self.
class ThreadId {
public:
ThreadId() {}
virtual ~ThreadId();
virtual bool IsEqual(const ThreadId& that) const = 0;
virtual bool IsCurrentThread() const = 0;
private:
DISALLOW_COPY_AND_ASSIGN(ThreadId);
};
enum ThreadFlags {
kDetached = 0,
kJoinable = 1
};
virtual ~ThreadSystem();
ThreadSystem() {}
// Makes a new mutex for this system.
//
// See also CondvarCapableMutex::NewCondvar.
virtual CondvarCapableMutex* NewMutex() = 0;
// This lock will provide following guarantee -
// - Reader reentrant safe.
// - Writer Priority, this ensures no writer starvation.
virtual RWLock* NewRWLock() = 0;
// Creates and returns a real-time timer. Caller is responsible for deleting.
//
// TODO(jmarantz): consider removing this and controlling timers separately.
virtual Timer* NewTimer() = 0;
// Returns an object holding the current thread ID. The resultant object must
// be freed by the caller.
virtual ThreadId* GetThreadId() const = 0;
private:
friend class Thread;
friend class MockThreadSystem;
friend class CheckingThreadSystem;
virtual ThreadImpl* NewThreadImpl(Thread* wrapper, ThreadFlags flags) = 0;
DISALLOW_COPY_AND_ASSIGN(ThreadSystem);
};
// ThreadImpl is the class that's inherited off when implementing threading ---
// ThreadSystem::NewThreadImpl is responsible for creating an appropriate
// instance that's hooked up to a given user Thread object.
class ThreadSystem::ThreadImpl {
public:
virtual bool StartImpl() = 0;
virtual void JoinImpl() = 0;
virtual ~ThreadImpl();
protected:
ThreadImpl() {}
private:
DISALLOW_COPY_AND_ASSIGN(ThreadImpl);
};
// Catch bug where variable name is omitted with ScopedReader, e.g.
// ThreadSystem::ScopedReader(&lock);
#define ScopedReader(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name)
} // namespace net_instaweb
#endif // PAGESPEED_KERNEL_BASE_THREAD_SYSTEM_H_