Index: runtime/vm/os_thread.h |
diff --git a/runtime/vm/os_thread.h b/runtime/vm/os_thread.h |
index 5929ef4503ff1aed8bf3f1fc79373d9323428e02..f01c4a2685c40a91d6e02e779760b215dd4c1554 100644 |
--- a/runtime/vm/os_thread.h |
+++ b/runtime/vm/os_thread.h |
@@ -6,6 +6,7 @@ |
#define VM_OS_THREAD_H_ |
#include "platform/globals.h" |
+#include "vm/allocation.h" |
#include "vm/globals.h" |
// Declare the OS-specific types ahead of defining the generic classes. |
@@ -23,13 +24,125 @@ |
namespace dart { |
+// Forward declarations. |
+class Log; |
+class Mutex; |
+class Thread; |
+class TimelineEventBlock; |
+ |
+class BaseThread { |
+ public: |
+ bool is_os_thread() const { return is_os_thread_; } |
+ |
+ private: |
+ explicit BaseThread(bool is_os_thread) : is_os_thread_(is_os_thread) {} |
+ ~BaseThread() {} |
+ |
+ bool is_os_thread_; |
+ |
+ friend class Thread; |
+ friend class OSThread; |
+ |
+ DISALLOW_IMPLICIT_CONSTRUCTORS(BaseThread); |
+}; |
+ |
+ |
// Low-level operations on OS platform threads. |
-// TODO(koda): Move to runtime/platform. |
-class OSThread { |
+class OSThread : public BaseThread { |
public: |
- static ThreadLocalKey kUnsetThreadLocalKey; |
- static ThreadId kInvalidThreadId; |
- static ThreadJoinId kInvalidThreadJoinId; |
+ OSThread(); |
+ ~OSThread(); |
+ |
+ ThreadId id() const { |
+ ASSERT(id_ != OSThread::kInvalidThreadId); |
+ return id_; |
+ } |
+ |
+ ThreadId join_id() const { |
+ ASSERT(join_id_ != OSThread::kInvalidThreadJoinId); |
+ return join_id_; |
+ } |
+ |
+ ThreadId trace_id() const { |
+ ASSERT(trace_id_ != OSThread::kInvalidThreadJoinId); |
+ return trace_id_; |
+ } |
+ |
+ const char* name() const { |
+ return name_; |
+ } |
+ |
+ void set_name(const char* name) { |
+ ASSERT(OSThread::Current() == this); |
+ ASSERT(name_ == NULL); |
+ name_ = name; |
+ } |
+ |
+ Mutex* timeline_block_lock() const { |
+ return timeline_block_lock_; |
+ } |
+ |
+ // Only safe to access when holding |timeline_block_lock_|. |
+ TimelineEventBlock* timeline_block() const { |
+ return timeline_block_; |
+ } |
+ |
+ // Only safe to access when holding |timeline_block_lock_|. |
+ void set_timeline_block(TimelineEventBlock* block) { |
+ timeline_block_ = block; |
+ } |
+ |
+ Log* log() const { return log_; } |
+ |
+ uword stack_base() const { return stack_base_; } |
+ void set_stack_base(uword stack_base) { stack_base_ = stack_base; } |
+ |
+ // Retrieve the stack address bounds for profiler. |
+ bool GetProfilerStackBounds(uword* lower, uword* upper) const { |
+ uword stack_upper = stack_base_; |
+ if (stack_upper == 0) { |
+ return false; |
+ } |
+ uword stack_lower = stack_upper - GetSpecifiedStackSize(); |
+ *lower = stack_lower; |
+ *upper = stack_upper; |
+ return true; |
+ } |
+ |
+ // Used to temporarily disable or enable thread interrupts. |
+ void DisableThreadInterrupts(); |
+ void EnableThreadInterrupts(); |
+ bool ThreadInterruptsEnabled(); |
+ |
+ // The currently executing thread, or NULL if not yet initialized. |
+ static OSThread* Current() { |
+ BaseThread* thread = GetCurrentTLS(); |
+ OSThread* os_thread = NULL; |
+ if (thread != NULL) { |
+ if (thread->is_os_thread()) { |
+ os_thread = reinterpret_cast<OSThread*>(thread); |
+ } else { |
+ Thread* vm_thread = reinterpret_cast<Thread*>(thread); |
+ os_thread = GetOSThreadFromThread(vm_thread); |
+ } |
+ } |
+ return os_thread; |
+ } |
+ static void SetCurrent(OSThread* current); |
+ |
+ // TODO(5411455): Use flag to override default value and Validate the |
+ // stack size by querying OS. |
+ static uword GetSpecifiedStackSize() { |
+ ASSERT(OSThread::kStackSizeBuffer < OSThread::GetMaxStackSize()); |
+ uword stack_size = OSThread::GetMaxStackSize() - OSThread::kStackSizeBuffer; |
+ return stack_size; |
+ } |
+ static BaseThread* GetCurrentTLS() { |
+ return reinterpret_cast<BaseThread*>(OSThread::GetThreadLocal(thread_key_)); |
+ } |
+ static void SetCurrentTLS(uword value) { |
+ SetThreadLocal(thread_key_, value); |
+ } |
typedef void (*ThreadStartFunction) (uword parameter); |
typedef void (*ThreadDestructor) (void* parameter); |
@@ -37,26 +150,95 @@ class OSThread { |
// Start a thread running the specified function. Returns 0 if the |
// thread started successfuly and a system specific error code if |
// the thread failed to start. |
- static int Start(ThreadStartFunction function, uword parameters); |
+ static int Start( |
+ const char* name, ThreadStartFunction function, uword parameter); |
static ThreadLocalKey CreateThreadLocal(ThreadDestructor destructor = NULL); |
static void DeleteThreadLocal(ThreadLocalKey key); |
static uword GetThreadLocal(ThreadLocalKey key) { |
return ThreadInlineImpl::GetThreadLocal(key); |
} |
+ static ThreadId GetCurrentThreadId(); |
static void SetThreadLocal(ThreadLocalKey key, uword value); |
static intptr_t GetMaxStackSize(); |
- static ThreadId GetCurrentThreadId(); |
- static ThreadId GetCurrentThreadTraceId(); |
- static intptr_t CurrentCurrentThreadIdAsIntPtr() { |
- return ThreadIdToIntPtr(GetCurrentThreadId()); |
- } |
- static ThreadJoinId GetCurrentThreadJoinId(); |
static void Join(ThreadJoinId id); |
static intptr_t ThreadIdToIntPtr(ThreadId id); |
static ThreadId ThreadIdFromIntPtr(intptr_t id); |
static bool Compare(ThreadId a, ThreadId b); |
static void GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage); |
+ |
+ // Called at VM startup and shutdown. |
+ static void InitOnce(); |
+ |
+ static bool IsThreadInList(ThreadId join_id); |
+ |
+ static const intptr_t kStackSizeBuffer = (4 * KB * kWordSize); |
+ |
+ static ThreadLocalKey kUnsetThreadLocalKey; |
+ static ThreadId kInvalidThreadId; |
+ static ThreadJoinId kInvalidThreadJoinId; |
+ |
+ private: |
+ // These methods should not be used in a generic way and hence |
+ // are private, they have been added to solve the problem of |
+ // accessing the VM thread structure from an OSThread object |
+ // in the windows thread interrupter which is used for profiling. |
+ // We could eliminate this requirement if the windows thread interrupter |
+ // is implemented differently. |
+ Thread* thread() const { return thread_; } |
+ void set_thread(Thread* value) { |
+ thread_ = value; |
+ } |
+ |
+ static void Cleanup(); |
+ static ThreadId GetCurrentThreadTraceId(); |
+ static ThreadJoinId GetCurrentThreadJoinId(); |
+ static OSThread* GetOSThreadFromThread(Thread* thread); |
+ static void AddThreadToList(OSThread* thread); |
+ static void RemoveThreadFromList(OSThread* thread); |
+ |
+ static ThreadLocalKey thread_key_; |
+ |
+ const ThreadId id_; |
+ const ThreadId join_id_; |
+ const ThreadId trace_id_; // Used to interface with tracing tools. |
+ const char* name_; // A name for this thread. |
+ |
+ Mutex* timeline_block_lock_; |
+ TimelineEventBlock* timeline_block_; |
+ |
+ // All |Thread|s are registered in the thread list. |
+ OSThread* thread_list_next_; |
+ |
+ uintptr_t thread_interrupt_disabled_; |
+ Log* log_; |
+ uword stack_base_; |
+ Thread* thread_; |
+ |
+ static OSThread* thread_list_head_; |
+ static Mutex* thread_list_lock_; |
+ |
+ friend class OSThreadIterator; |
+ friend class ThreadInterrupterWin; |
+ friend class ThreadRegistry; |
+}; |
+ |
+ |
+// Note that this takes the thread list lock, prohibiting threads from coming |
+// on- or off-line. |
+class OSThreadIterator : public ValueObject { |
+ public: |
+ OSThreadIterator(); |
+ ~OSThreadIterator(); |
+ |
+ // Returns false when there are no more threads left. |
+ bool HasNext() const; |
+ |
+ // Returns the current thread and moves forward. |
+ OSThread* Next(); |
+ |
+ private: |
+ OSThread* next_; |
}; |