Bug 1062715 - remove Chromium event recorder, memory debug, simple thread, drag and drop code. rs=bent

This commit is contained in:
Josh Aas 2014-09-03 23:56:40 -05:00
parent 19586b7c3c
commit db6fd5144c
11 changed files with 0 additions and 978 deletions

View File

@ -2,8 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "base/linked_ptr.h"
#include "mozilla/ModuleUtils.h"
#include "nsIClassInfoImpl.h"

View File

@ -45,7 +45,6 @@ UNIFIED_SOURCES += [
'src/base/lazy_instance.cc',
'src/base/lock.cc',
'src/base/logging.cc',
'src/base/memory_debug.cc',
'src/base/message_loop.cc',
'src/base/message_pump_default.cc',
'src/base/non_thread_safe.cc',
@ -54,7 +53,6 @@ UNIFIED_SOURCES += [
'src/base/ref_counted.cc',
'src/base/revocable_store.cc',
'src/base/scoped_temp_dir.cc',
'src/base/simple_thread.cc',
'src/base/string_piece.cc',
'src/base/string_util.cc',
'src/base/thread.cc',
@ -84,7 +82,6 @@ if os_win:
SOURCES += [
'src/base/condition_variable_win.cc',
'src/base/cpu.cc',
'src/base/event_recorder.cc',
'src/base/file_util_win.cc',
'src/base/idle_timer.cc',
'src/base/lock_impl_win.cc',
@ -141,7 +138,6 @@ elif not CONFIG['MOZ_NATIVE_LIBEVENT']:
if os_posix:
SOURCES += [
'src/base/condition_variable_posix.cc',
'src/base/event_recorder_stubs.cc',
'src/base/file_descriptor_shuffle.cc',
'src/base/file_util_posix.cc',
'src/base/lock_impl_posix.cc',

View File

@ -1,46 +0,0 @@
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_BASE_DRAG_SOURCE_H_
#define BASE_BASE_DRAG_SOURCE_H_
#include <objidl.h>
#include "base/basictypes.h"
///////////////////////////////////////////////////////////////////////////////
//
// BaseDragSource
//
// A base IDropSource implementation. Handles notifications sent by an active
// drag-drop operation as the user mouses over other drop targets on their
// system. This object tells Windows whether or not the drag should continue,
// and supplies the appropriate cursors.
//
class BaseDragSource : public IDropSource {
public:
BaseDragSource();
virtual ~BaseDragSource() { }
// IDropSource implementation:
HRESULT __stdcall QueryContinueDrag(BOOL escape_pressed, DWORD key_state);
HRESULT __stdcall GiveFeedback(DWORD effect);
// IUnknown implementation:
HRESULT __stdcall QueryInterface(const IID& iid, void** object);
ULONG __stdcall AddRef();
ULONG __stdcall Release();
protected:
virtual void OnDragSourceCancel() { }
virtual void OnDragSourceDrop() { }
virtual void OnDragSourceMove() { }
private:
LONG ref_count_;
DISALLOW_EVIL_CONSTRUCTORS(BaseDragSource);
};
#endif // BASE_BASE_DRAG_SOURCE_H_

View File

@ -1,130 +0,0 @@
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_BASE_DROP_TARGET_H_
#define BASE_BASE_DROP_TARGET_H_
#include <objidl.h>
#include "base/ref_counted.h"
struct IDropTargetHelper;
// A DropTarget implementation that takes care of the nitty gritty
// of dnd. While this class is concrete, subclasses will most likely
// want to override various OnXXX methods.
//
// Because BaseDropTarget is ref counted you shouldn't delete it directly,
// rather wrap it in a scoped_refptr. Be sure and invoke RevokeDragDrop(m_hWnd)
// before the HWND is deleted too.
//
// This class is meant to be used in a STA and is not multithread-safe.
class BaseDropTarget : public IDropTarget {
public:
// Create a new BaseDropTarget associating it with the given HWND.
explicit BaseDropTarget(HWND hwnd);
virtual ~BaseDropTarget();
// When suspend is set to |true|, the drop target does not receive drops from
// drags initiated within the owning HWND.
// TODO(beng): (http://b/1085385) figure out how we will handle legitimate
// drag-drop operations within the same HWND, such as dragging
// selected text to an edit field.
void set_suspend(bool suspend) { suspend_ = suspend; }
// IDropTarget implementation:
HRESULT __stdcall DragEnter(IDataObject* data_object,
DWORD key_state,
POINTL cursor_position,
DWORD* effect);
HRESULT __stdcall DragOver(DWORD key_state,
POINTL cursor_position,
DWORD* effect);
HRESULT __stdcall DragLeave();
HRESULT __stdcall Drop(IDataObject* data_object,
DWORD key_state,
POINTL cursor_position,
DWORD* effect);
// IUnknown implementation:
HRESULT __stdcall QueryInterface(const IID& iid, void** object);
ULONG __stdcall AddRef();
ULONG __stdcall Release();
protected:
// Returns the hosting HWND.
HWND GetHWND() { return hwnd_; }
// Invoked when the cursor first moves over the hwnd during a dnd session.
// This should return a bitmask of the supported drop operations:
// DROPEFFECT_NONE, DROPEFFECT_COPY, DROPEFFECT_LINK and/or
// DROPEFFECT_MOVE.
virtual DWORD OnDragEnter(IDataObject* data_object,
DWORD key_state,
POINT cursor_position,
DWORD effect);
// Invoked when the cursor moves over the window during a dnd session.
// This should return a bitmask of the supported drop operations:
// DROPEFFECT_NONE, DROPEFFECT_COPY, DROPEFFECT_LINK and/or
// DROPEFFECT_MOVE.
virtual DWORD OnDragOver(IDataObject* data_object,
DWORD key_state,
POINT cursor_position,
DWORD effect);
// Invoked when the cursor moves outside the bounds of the hwnd during a
// dnd session.
virtual void OnDragLeave(IDataObject* data_object);
// Invoked when the drop ends on the window. This should return the operation
// that was taken.
virtual DWORD OnDrop(IDataObject* data_object,
DWORD key_state,
POINT cursor_position,
DWORD effect);
// Return the drag identity.
static int32_t GetDragIdentity() { return drag_identity_; }
private:
// Returns the cached drop helper, creating one if necessary. The returned
// object is not addrefed. May return NULL if the object couldn't be created.
static IDropTargetHelper* DropHelper();
// The data object currently being dragged over this drop target.
scoped_refptr<IDataObject> current_data_object_;
// A helper object that is used to provide drag image support while the mouse
// is dragging over the content area.
//
// DO NOT ACCESS DIRECTLY! Use DropHelper() instead, which will lazily create
// this if it doesn't exist yet. This object can take tens of milliseconds to
// create, and we don't want to block any window opening for this, especially
// since often, DnD will never be used. Instead, we force this penalty to the
// first time it is actually used.
static IDropTargetHelper* cached_drop_target_helper_;
// The drag identity (id). An up-counter that increases when the cursor first
// moves over the HWND in a DnD session (OnDragEnter). 0 is reserved to mean
// the "no/unknown" identity, and is used for initialization. The identity is
// sent to the renderer in drag enter notifications. Note: the identity value
// is passed over the renderer NPAPI interface to gears, so use int32_t instead
// of int here.
static int32_t drag_identity_;
// The HWND of the source. This HWND is used to determine coordinates for
// mouse events that are sent to the renderer notifying various drag states.
HWND hwnd_;
// Whether or not we are currently processing drag notifications for drags
// initiated in this window.
bool suspend_;
LONG ref_count_;
DISALLOW_EVIL_CONSTRUCTORS(BaseDropTarget);
};
#endif // BASE_BASE_DROP_TARGET_H_

View File

@ -1,259 +0,0 @@
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "build/build_config.h"
#include <windows.h>
#include <mmsystem.h>
#include "base/event_recorder.h"
#include "base/file_util.h"
#include "base/logging.h"
// A note about time.
// For perfect playback of events, you'd like a very accurate timer
// so that events are played back at exactly the same time that
// they were recorded. However, windows has a clock which is only
// granular to ~15ms. We see more consistent event playback when
// using a higher resolution timer. To do this, we use the
// timeGetTime API instead of the default GetTickCount() API.
namespace base {
EventRecorder* EventRecorder::current_ = NULL;
LRESULT CALLBACK StaticRecordWndProc(int nCode, WPARAM wParam,
LPARAM lParam) {
CHECK(EventRecorder::current());
return EventRecorder::current()->RecordWndProc(nCode, wParam, lParam);
}
LRESULT CALLBACK StaticPlaybackWndProc(int nCode, WPARAM wParam,
LPARAM lParam) {
CHECK(EventRecorder::current());
return EventRecorder::current()->PlaybackWndProc(nCode, wParam, lParam);
}
EventRecorder::~EventRecorder() {
// Try to assert early if the caller deletes the recorder
// while it is still in use.
DCHECK(!journal_hook_);
DCHECK(!is_recording_ && !is_playing_);
}
bool EventRecorder::StartRecording(const FilePath& filename) {
if (journal_hook_ != NULL)
return false;
if (is_recording_ || is_playing_)
return false;
// Open the recording file.
DCHECK(file_ == NULL);
file_ = file_util::OpenFile(filename, "wb+");
if (!file_) {
DLOG(ERROR) << "EventRecorder could not open log file";
return false;
}
// Set the faster clock, if possible.
::timeBeginPeriod(1);
// Set the recording hook. JOURNALRECORD can only be used as a global hook.
journal_hook_ = ::SetWindowsHookEx(WH_JOURNALRECORD, StaticRecordWndProc,
GetModuleHandle(NULL), 0);
if (!journal_hook_) {
DLOG(ERROR) << "EventRecorder Record Hook failed";
file_util::CloseFile(file_);
return false;
}
is_recording_ = true;
return true;
}
void EventRecorder::StopRecording() {
if (is_recording_) {
DCHECK(journal_hook_ != NULL);
if (!::UnhookWindowsHookEx(journal_hook_)) {
DLOG(ERROR) << "EventRecorder Unhook failed";
// Nothing else we can really do here.
return;
}
::timeEndPeriod(1);
DCHECK(file_ != NULL);
file_util::CloseFile(file_);
file_ = NULL;
journal_hook_ = NULL;
is_recording_ = false;
}
}
bool EventRecorder::StartPlayback(const FilePath& filename) {
if (journal_hook_ != NULL)
return false;
if (is_recording_ || is_playing_)
return false;
// Open the recording file.
DCHECK(file_ == NULL);
file_ = file_util::OpenFile(filename, "rb");
if (!file_) {
DLOG(ERROR) << "EventRecorder Playback could not open log file";
return false;
}
// Read the first event from the record.
if (fread(&playback_msg_, sizeof(EVENTMSG), 1, file_) != 1) {
DLOG(ERROR) << "EventRecorder Playback has no records!";
file_util::CloseFile(file_);
return false;
}
// Set the faster clock, if possible.
::timeBeginPeriod(1);
// Playback time is tricky. When playing back, we read a series of events,
// each with timeouts. Simply subtracting the delta between two timers will
// lead to fast playback (about 2x speed). The API has two events, one
// which advances to the next event (HC_SKIP), and another that requests the
// event (HC_GETNEXT). The same event will be requested multiple times.
// Each time the event is requested, we must calculate the new delay.
// To do this, we track the start time of the playback, and constantly
// re-compute the delay. I mention this only because I saw two examples
// of how to use this code on the net, and both were broken :-)
playback_start_time_ = timeGetTime();
playback_first_msg_time_ = playback_msg_.time;
// Set the hook. JOURNALPLAYBACK can only be used as a global hook.
journal_hook_ = ::SetWindowsHookEx(WH_JOURNALPLAYBACK, StaticPlaybackWndProc,
GetModuleHandle(NULL), 0);
if (!journal_hook_) {
DLOG(ERROR) << "EventRecorder Playback Hook failed";
return false;
}
is_playing_ = true;
return true;
}
void EventRecorder::StopPlayback() {
if (is_playing_) {
DCHECK(journal_hook_ != NULL);
if (!::UnhookWindowsHookEx(journal_hook_)) {
DLOG(ERROR) << "EventRecorder Unhook failed";
// Nothing else we can really do here.
}
DCHECK(file_ != NULL);
file_util::CloseFile(file_);
file_ = NULL;
::timeEndPeriod(1);
journal_hook_ = NULL;
is_playing_ = false;
}
}
// Windows callback hook for the recorder.
LRESULT EventRecorder::RecordWndProc(int nCode, WPARAM wParam, LPARAM lParam) {
static bool recording_enabled = true;
EVENTMSG* msg_ptr = NULL;
// The API says we have to do this.
// See http://msdn2.microsoft.com/en-us/library/ms644983(VS.85).aspx
if (nCode < 0)
return ::CallNextHookEx(journal_hook_, nCode, wParam, lParam);
// Check for the break key being pressed and stop recording.
if (::GetKeyState(VK_CANCEL) & 0x8000) {
StopRecording();
return ::CallNextHookEx(journal_hook_, nCode, wParam, lParam);
}
// The Journal Recorder must stop recording events when system modal
// dialogs are present. (see msdn link above)
switch(nCode) {
case HC_SYSMODALON:
recording_enabled = false;
break;
case HC_SYSMODALOFF:
recording_enabled = true;
break;
}
if (nCode == HC_ACTION && recording_enabled) {
// Aha - we have an event to record.
msg_ptr = reinterpret_cast<EVENTMSG*>(lParam);
msg_ptr->time = timeGetTime();
fwrite(msg_ptr, sizeof(EVENTMSG), 1, file_);
fflush(file_);
}
return CallNextHookEx(journal_hook_, nCode, wParam, lParam);
}
// Windows callback for the playback mode.
LRESULT EventRecorder::PlaybackWndProc(int nCode, WPARAM wParam,
LPARAM lParam) {
static bool playback_enabled = true;
int delay = 0;
switch(nCode) {
// A system modal dialog box is being displayed. Stop playing back
// messages.
case HC_SYSMODALON:
playback_enabled = false;
break;
// A system modal dialog box is destroyed. We can start playing back
// messages again.
case HC_SYSMODALOFF:
playback_enabled = true;
break;
// Prepare to copy the next mouse or keyboard event to playback.
case HC_SKIP:
if (!playback_enabled)
break;
// Read the next event from the record.
if (fread(&playback_msg_, sizeof(EVENTMSG), 1, file_) != 1)
this->StopPlayback();
break;
// Copy the mouse or keyboard event to the EVENTMSG structure in lParam.
case HC_GETNEXT:
if (!playback_enabled)
break;
memcpy(reinterpret_cast<void*>(lParam), &playback_msg_,
sizeof(playback_msg_));
// The return value is the amount of time (in milliseconds) to wait
// before playing back the next message in the playback queue. Each
// time this is called, we recalculate the delay relative to our current
// wall clock.
delay = (playback_msg_.time - playback_first_msg_time_) -
(timeGetTime() - playback_start_time_);
if (delay < 0)
delay = 0;
return delay;
// An application has called PeekMessage with wRemoveMsg set to PM_NOREMOVE
// indicating that the message is not removed from the message queue after
// PeekMessage processing.
case HC_NOREMOVE:
break;
}
return CallNextHookEx(journal_hook_, nCode, wParam, lParam);
}
} // namespace base

View File

@ -1,102 +0,0 @@
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_EVENT_RECORDER_H_
#define BASE_EVENT_RECORDER_H_
#include <string>
#if defined(OS_WIN)
#include <windows.h>
#endif
#include "base/basictypes.h"
class FilePath;
namespace base {
// A class for recording and playing back keyboard and mouse input events.
//
// Note - if you record events, and the playback with the windows in
// different sizes or positions, the playback will fail. When
// recording and playing, you should move the relevant windows
// to constant sizes and locations.
// TODO(mbelshe) For now this is a singleton. I believe that this class
// could be easily modified to:
// support two simultaneous recorders
// be playing back events while already recording events.
// Why? Imagine if the product had a "record a macro" feature.
// You might be recording globally, while recording or playing back
// a macro. I don't think two playbacks make sense.
class EventRecorder {
public:
// Get the singleton EventRecorder.
// We can only handle one recorder/player at a time.
static EventRecorder* current() {
if (!current_)
current_ = new EventRecorder();
return current_;
}
// Starts recording events.
// Will clobber the file if it already exists.
// Returns true on success, or false if an error occurred.
bool StartRecording(const FilePath& filename);
// Stops recording.
void StopRecording();
// Is the EventRecorder currently recording.
bool is_recording() const { return is_recording_; }
// Plays events previously recorded.
// Returns true on success, or false if an error occurred.
bool StartPlayback(const FilePath& filename);
// Stops playback.
void StopPlayback();
// Is the EventRecorder currently playing.
bool is_playing() const { return is_playing_; }
#if defined(OS_WIN)
// C-style callbacks for the EventRecorder.
// Used for internal purposes only.
LRESULT RecordWndProc(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT PlaybackWndProc(int nCode, WPARAM wParam, LPARAM lParam);
#endif
private:
// Create a new EventRecorder. Events are saved to the file filename.
// If the file already exists, it will be deleted before recording
// starts.
explicit EventRecorder()
: is_recording_(false),
is_playing_(false),
#if defined(OS_WIN)
journal_hook_(NULL),
file_(NULL),
#endif
playback_first_msg_time_(0),
playback_start_time_(0) {
}
~EventRecorder();
static EventRecorder* current_; // Our singleton.
bool is_recording_;
bool is_playing_;
#if defined(OS_WIN)
HHOOK journal_hook_;
FILE* file_;
EVENTMSG playback_msg_;
#endif
int playback_first_msg_time_;
int playback_start_time_;
DISALLOW_EVIL_CONSTRUCTORS(EventRecorder);
};
} // namespace base
#endif // BASE_EVENT_RECORDER_H_

View File

@ -1,28 +0,0 @@
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/event_recorder.h"
// This file implements a link stub for EventRecorder that can be used on
// platforms that don't have a working EventRecorder implementation.
namespace base {
EventRecorder* EventRecorder::current_; // Our singleton.
bool EventRecorder::StartRecording(const FilePath& filename) {
return true;
}
void EventRecorder::StopRecording() {
}
bool EventRecorder::StartPlayback(const FilePath& filename) {
return false;
}
void EventRecorder::StopPlayback() {
}
} // namespace

View File

@ -1,54 +0,0 @@
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/memory_debug.h"
#ifdef PURIFY
// this #define is used to prevent people from directly using pure.h
// instead of memory_debug.h
#define PURIFY_PRIVATE_INCLUDE
#include "base/third_party/purify/pure.h"
#endif
namespace base {
bool MemoryDebug::memory_in_use_ = false;
void MemoryDebug::SetMemoryInUseEnabled(bool enabled) {
memory_in_use_ = enabled;
}
void MemoryDebug::DumpAllMemoryInUse() {
#ifdef PURIFY
if (memory_in_use_)
PurifyAllInuse();
#endif
}
void MemoryDebug::DumpNewMemoryInUse() {
#ifdef PURIFY
if (memory_in_use_)
PurifyNewInuse();
#endif
}
void MemoryDebug::DumpAllLeaks() {
#ifdef PURIFY
PurifyAllLeaks();
#endif
}
void MemoryDebug::DumpNewLeaks() {
#ifdef PURIFY
PurifyNewLeaks();
#endif
}
void MemoryDebug::MarkAsInitialized(void* addr, size_t size) {
#ifdef PURIFY
PurifyMarkAsInitialized(addr, size);
#endif
}
} // namespace base

View File

@ -1,46 +0,0 @@
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Functions used to debug memory usage, leaks, and other memory issues.
// All methods are effectively no-ops unless this program is being run through
// a supported memory tool (currently, only Purify)
#ifndef BASE_MEMORY_DEBUG_H_
#define BASE_MEMORY_DEBUG_H_
#include "base/basictypes.h"
namespace base {
class MemoryDebug {
public:
// Since MIU messages are a lot of data, and we don't always want this data,
// we have a global switch. If disabled, *MemoryInUse are no-ops.
static void SetMemoryInUseEnabled(bool enabled);
// Dump information about all memory in use.
static void DumpAllMemoryInUse();
// Dump information about new memory in use since the last
// call to DumpAllMemoryInUse() or DumpNewMemoryInUse().
static void DumpNewMemoryInUse();
// Dump information about all current memory leaks.
static void DumpAllLeaks();
// Dump information about new memory leaks since the last
// call to DumpAllLeaks() or DumpNewLeaks()
static void DumpNewLeaks();
// Mark |size| bytes of memory as initialized, so it doesn't produce any UMRs
// or UMCs.
static void MarkAsInitialized(void* addr, size_t size);
private:
static bool memory_in_use_;
DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryDebug);
};
} // namespace base
#endif // BASE_MEMORY_DEBUG_H_

View File

@ -1,118 +0,0 @@
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/simple_thread.h"
#include "base/waitable_event.h"
#include "base/logging.h"
#include "base/platform_thread.h"
#include "base/string_util.h"
namespace base {
void SimpleThread::Start() {
DCHECK(!HasBeenStarted()) << "Tried to Start a thread multiple times.";
bool success = PlatformThread::Create(options_.stack_size(), this, &thread_);
CHECK(success);
event_.Wait(); // Wait for the thread to complete initialization.
}
void SimpleThread::Join() {
DCHECK(HasBeenStarted()) << "Tried to Join a never-started thread.";
DCHECK(!HasBeenJoined()) << "Tried to Join a thread multiple times.";
PlatformThread::Join(thread_);
joined_ = true;
}
void SimpleThread::ThreadMain() {
tid_ = PlatformThread::CurrentId();
// Construct our full name of the form "name_prefix_/TID".
name_.push_back('/');
name_.append(IntToString(tid_));
PlatformThread::SetName(name_.c_str());
// We've initialized our new thread, signal that we're done to Start().
event_.Signal();
Run();
}
SimpleThread::~SimpleThread() {
DCHECK(HasBeenStarted()) << "SimpleThread was never started.";
DCHECK(HasBeenJoined()) << "SimpleThread destroyed without being Join()ed.";
}
void DelegateSimpleThread::Run() {
DCHECK(delegate_) << "Tried to call Run without a delegate (called twice?)";
delegate_->Run();
delegate_ = NULL;
}
DelegateSimpleThreadPool::~DelegateSimpleThreadPool() {
DCHECK(threads_.empty());
DCHECK(delegates_.empty());
DCHECK(!dry_.IsSignaled());
}
void DelegateSimpleThreadPool::Start() {
DCHECK(threads_.empty()) << "Start() called with outstanding threads.";
for (int i = 0; i < num_threads_; ++i) {
DelegateSimpleThread* thread = new DelegateSimpleThread(this, name_prefix_);
thread->Start();
threads_.push_back(thread);
}
}
void DelegateSimpleThreadPool::JoinAll() {
DCHECK(!threads_.empty()) << "JoinAll() called with no outstanding threads.";
// Tell all our threads to quit their worker loop.
AddWork(NULL, num_threads_);
// Join and destroy all the worker threads.
for (int i = 0; i < num_threads_; ++i) {
threads_[i]->Join();
delete threads_[i];
}
threads_.clear();
DCHECK(delegates_.empty());
}
void DelegateSimpleThreadPool::AddWork(Delegate* delegate, int repeat_count) {
AutoLock locked(lock_);
for (int i = 0; i < repeat_count; ++i)
delegates_.push(delegate);
// If we were empty, signal that we have work now.
if (!dry_.IsSignaled())
dry_.Signal();
}
void DelegateSimpleThreadPool::Run() {
Delegate* work;
while (true) {
dry_.Wait();
{
AutoLock locked(lock_);
if (!dry_.IsSignaled())
continue;
DCHECK(!delegates_.empty());
work = delegates_.front();
delegates_.pop();
// Signal to any other threads that we're currently out of work.
if (delegates_.empty())
dry_.Reset();
}
// A NULL delegate pointer signals us to quit.
if (!work)
break;
work->Run();
}
}
} // namespace base

View File

@ -1,189 +0,0 @@
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// WARNING: You should probably be using Thread (thread.h) instead. Thread is
// Chrome's message-loop based Thread abstraction, and if you are a
// thread running in the browser, there will likely be assumptions
// that your thread will have an associated message loop.
//
// This is a simple thread interface that backs to a native operating system
// thread. You should use this only when you want a thread that does not have
// an associated MessageLoop. Unittesting is the best example of this.
//
// The simplest interface to use is DelegateSimpleThread, which will create
// a new thread, and execute the Delegate's virtual Run() in this new thread
// until it has completed, exiting the thread.
//
// NOTE: You *MUST* call Join on the thread to clean up the underlying thread
// resources. You are also responsible for destructing the SimpleThread object.
// It is invalid to destroy a SimpleThread while it is running, or without
// Start() having been called (and a thread never created). The Delegate
// object should live as long as a DelegateSimpleThread.
//
// Thread Safety: A SimpleThread is not completely thread safe. It is safe to
// access it from the creating thread or from the newly created thread. This
// implies that the creator thread should be the thread that calls Join.
//
// Example:
// class MyThreadRunner : public DelegateSimpleThread::Delegate { ... };
// MyThreadRunner runner;
// DelegateSimpleThread thread(&runner, "good_name_here");
// thread.Start();
// // Start will return after the Thread has been successfully started and
// // initialized. The newly created thread will invoke runner->Run(), and
// // run until it returns.
// thread.Join(); // Wait until the thread has exited. You *MUST* Join!
// // The SimpleThread object is still valid, however you may not call Join
// // or Start again.
#ifndef BASE_SIMPLE_THREAD_H_
#define BASE_SIMPLE_THREAD_H_
#include <string>
#include <queue>
#include <vector>
#include "base/basictypes.h"
#include "base/lock.h"
#include "base/waitable_event.h"
#include "base/platform_thread.h"
namespace base {
// This is the base SimpleThread. You can derive from it and implement the
// virtual Run method, or you can use the DelegateSimpleThread interface.
class SimpleThread : public PlatformThread::Delegate {
public:
class Options {
public:
Options() : stack_size_(0) { }
~Options() { }
// We use the standard compiler-supplied copy constructor.
// A custom stack size, or 0 for the system default.
void set_stack_size(size_t size) { stack_size_ = size; }
size_t stack_size() const { return stack_size_; }
private:
size_t stack_size_;
};
// Create a SimpleThread. |options| should be used to manage any specific
// configuration involving the thread creation and management.
// Every thread has a name, in the form of |name_prefix|/TID, for example
// "my_thread/321". The thread will not be created until Start() is called.
explicit SimpleThread(const std::string& name_prefix)
: name_prefix_(name_prefix), name_(name_prefix),
thread_(), event_(true, false), tid_(0), joined_(false) { }
SimpleThread(const std::string& name_prefix, const Options& options)
: name_prefix_(name_prefix), name_(name_prefix), options_(options),
thread_(), event_(true, false), tid_(0), joined_(false) { }
virtual ~SimpleThread();
virtual void Start();
virtual void Join();
// We follow the PlatformThread Delegate interface.
virtual void ThreadMain();
// Subclasses should override the Run method.
virtual void Run() = 0;
// Return the thread name prefix, or "unnamed" if none was supplied.
std::string name_prefix() { return name_prefix_; }
// Return the completed name including TID, only valid after Start().
std::string name() { return name_; }
// Return the thread id, only valid after Start().
PlatformThreadId tid() { return tid_; }
// Return True if Start() has ever been called.
bool HasBeenStarted() { return event_.IsSignaled(); }
// Return True if Join() has evern been called.
bool HasBeenJoined() { return joined_; }
private:
const std::string name_prefix_;
std::string name_;
const Options options_;
PlatformThreadHandle thread_; // PlatformThread handle, invalid after Join!
WaitableEvent event_; // Signaled if Start() was ever called.
PlatformThreadId tid_; // The backing thread's id.
bool joined_; // True if Join has been called.
};
class DelegateSimpleThread : public SimpleThread {
public:
class Delegate {
public:
Delegate() { }
virtual ~Delegate() { }
virtual void Run() = 0;
};
DelegateSimpleThread(Delegate* delegate,
const std::string& name_prefix)
: SimpleThread(name_prefix), delegate_(delegate) { }
DelegateSimpleThread(Delegate* delegate,
const std::string& name_prefix,
const Options& options)
: SimpleThread(name_prefix, options), delegate_(delegate) { }
virtual ~DelegateSimpleThread() { }
virtual void Run();
private:
Delegate* delegate_;
};
// DelegateSimpleThreadPool allows you to start up a fixed number of threads,
// and then add jobs which will be dispatched to the threads. This is
// convenient when you have a lot of small work that you want done
// multi-threaded, but don't want to spawn a thread for each small bit of work.
//
// You just call AddWork() to add a delegate to the list of work to be done.
// JoinAll() will make sure that all outstanding work is processed, and wait
// for everything to finish. You can reuse a pool, so you can call Start()
// again after you've called JoinAll().
class DelegateSimpleThreadPool : public DelegateSimpleThread::Delegate {
public:
typedef DelegateSimpleThread::Delegate Delegate;
DelegateSimpleThreadPool(const std::string name_prefix, int num_threads)
: name_prefix_(name_prefix), num_threads_(num_threads),
dry_(true, false) { }
~DelegateSimpleThreadPool();
// Start up all of the underlying threads, and start processing work if we
// have any.
void Start();
// Make sure all outstanding work is finished, and wait for and destroy all
// of the underlying threads in the pool.
void JoinAll();
// It is safe to AddWork() any time, before or after Start().
// Delegate* should always be a valid pointer, NULL is reserved internally.
void AddWork(Delegate* work, int repeat_count);
void AddWork(Delegate* work) {
AddWork(work, 1);
}
// We implement the Delegate interface, for running our internal threads.
virtual void Run();
private:
const std::string name_prefix_;
int num_threads_;
std::vector<DelegateSimpleThread*> threads_;
std::queue<Delegate*> delegates_;
Lock lock_; // Locks delegates_
WaitableEvent dry_; // Not signaled when there is no work to do.
};
} // namespace base
#endif // BASE_SIMPLE_THREAD_H_