147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/*
247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *
447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org */
1047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifndef WEBRTC_BASE_SIGNALTHREAD_H_
1247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#define WEBRTC_BASE_SIGNALTHREAD_H_
1347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <string>
1547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/constructormagic.h"
1747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/sigslot.h"
1847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/thread.h"
1947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace rtc {
2147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org///////////////////////////////////////////////////////////////////////////////
2347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// SignalThread - Base class for worker threads.  The main thread should call
2447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//  Start() to begin work, and then follow one of these models:
2547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//   Normal: Wait for SignalWorkDone, and then call Release to destroy.
2647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//   Cancellation: Call Release(true), to abort the worker thread.
2747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//   Fire-and-forget: Call Release(false), which allows the thread to run to
2847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//    completion, and then self-destruct without further notification.
2947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//   Periodic tasks: Wait for SignalWorkDone, then eventually call Start()
3047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//    again to repeat the task. When the instance isn't needed anymore,
3147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//    call Release. DoWork, OnWorkStart and OnWorkStop are called again,
3247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//    on a new thread.
3347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//  The subclass should override DoWork() to perform the background task.  By
3447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//   periodically calling ContinueWork(), it can check for cancellation.
3547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//   OnWorkStart and OnWorkDone can be overridden to do pre- or post-work
3647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//   tasks in the context of the main thread.
3747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org///////////////////////////////////////////////////////////////////////////////
3847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgclass SignalThread
4047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    : public sigslot::has_slots<>,
4147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      protected MessageHandler {
4247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org public:
4347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SignalThread();
4447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Context: Main Thread.  Call before Start to change the worker's name.
4647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  bool SetName(const std::string& name, const void* obj);
4747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Context: Main Thread.  Call before Start to change the worker's priority.
4947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  bool SetPriority(ThreadPriority priority);
5047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Context: Main Thread.  Call to begin the worker thread.
5247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  void Start();
5347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Context: Main Thread.  If the worker thread is not running, deletes the
5547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // object immediately.  Otherwise, asks the worker thread to abort processing,
5647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // and schedules the object to be deleted once the worker exits.
5747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // SignalWorkDone will not be signalled.  If wait is true, does not return
5847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // until the thread is deleted.
5947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  void Destroy(bool wait);
6047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Context: Main Thread.  If the worker thread is complete, deletes the
6247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // object immediately.  Otherwise, schedules the object to be deleted once
6347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // the worker thread completes.  SignalWorkDone will be signalled.
6447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  void Release();
6547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Context: Main Thread.  Signalled when work is complete.
6747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  sigslot::signal1<SignalThread *> SignalWorkDone;
6847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  enum { ST_MSG_WORKER_DONE, ST_MSG_FIRST_AVAILABLE };
7047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org protected:
7247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  virtual ~SignalThread();
7347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Thread* worker() { return &worker_; }
7547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Context: Main Thread.  Subclass should override to do pre-work setup.
7747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  virtual void OnWorkStart() { }
7847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Context: Worker Thread.  Subclass should override to do work.
8047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  virtual void DoWork() = 0;
8147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
8247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Context: Worker Thread.  Subclass should call periodically to
8347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // dispatch messages and determine if the thread should terminate.
8447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  bool ContinueWork();
8547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
8647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Context: Worker Thread.  Subclass should override when extra work is
8747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // needed to abort the worker thread.
8847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  virtual void OnWorkStop() { }
8947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Context: Main Thread.  Subclass should override to do post-work cleanup.
9147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  virtual void OnWorkDone() { }
9247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Context: Any Thread.  If subclass overrides, be sure to call the base
9447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // implementation.  Do not use (message_id < ST_MSG_FIRST_AVAILABLE)
9547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  virtual void OnMessage(Message *msg);
9647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org private:
9847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  enum State {
9947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    kInit,            // Initialized, but not started
10047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    kRunning,         // Started and doing work
10147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    kReleasing,       // Same as running, but to be deleted when work is done
10247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    kComplete,        // Work is done
10347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    kStopping,        // Work is being interrupted
10447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  };
10547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
10647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  class Worker : public Thread {
10747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org   public:
10847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    explicit Worker(SignalThread* parent) : parent_(parent) {}
10947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    virtual ~Worker() { Stop(); }
11047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    virtual void Run() { parent_->Run(); }
11147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
11247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org   private:
11347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SignalThread* parent_;
11447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
11547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    DISALLOW_IMPLICIT_CONSTRUCTORS(Worker);
11647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  };
11747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
11846c93aa23855b429a7bd3c622842539bf5937d3dpbos@webrtc.org  class SCOPED_LOCKABLE EnterExit {
11947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org   public:
12046c93aa23855b429a7bd3c622842539bf5937d3dpbos@webrtc.org    explicit EnterExit(SignalThread* t) EXCLUSIVE_LOCK_FUNCTION(t->cs_)
12146c93aa23855b429a7bd3c622842539bf5937d3dpbos@webrtc.org        : t_(t) {
12247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      t_->cs_.Enter();
12347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // If refcount_ is zero then the object has already been deleted and we
12447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // will be double-deleting it in ~EnterExit()! (shouldn't happen)
12547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      ASSERT(t_->refcount_ != 0);
12647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      ++t_->refcount_;
12747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
12846c93aa23855b429a7bd3c622842539bf5937d3dpbos@webrtc.org    ~EnterExit() UNLOCK_FUNCTION() {
12947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      bool d = (0 == --t_->refcount_);
13047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      t_->cs_.Leave();
13147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (d)
13247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        delete t_;
13347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
13447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
13547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org   private:
13647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SignalThread* t_;
13747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
13847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    DISALLOW_IMPLICIT_CONSTRUCTORS(EnterExit);
13947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  };
14047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
14147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  void Run();
14247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  void OnMainThreadDestroyed();
14347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
14447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Thread* main_;
14547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Worker worker_;
14647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CriticalSection cs_;
14747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  State state_;
14847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int refcount_;
14947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
15047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  DISALLOW_COPY_AND_ASSIGN(SignalThread);
15147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
15247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
15347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org///////////////////////////////////////////////////////////////////////////////
15447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
15547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}  // namespace rtc
15647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
15747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif  // WEBRTC_BASE_SIGNALTHREAD_H_
158