Author: [email protected]
Date: Tue Mar 17 04:40:47 2009
New Revision: 1523

Modified:
    branches/bleeding_edge/src/d8.js
    branches/bleeding_edge/src/debug-delay.js
    branches/bleeding_edge/src/runtime.cc
    branches/bleeding_edge/src/runtime.h
    branches/bleeding_edge/src/v8threads.cc
    branches/bleeding_edge/src/v8threads.h

Log:
Add thread information to the debugger.

Each thread running V8 code is assigned an id in thread local storage the  
first time V8 code is run in it. The thread information returned to the  
debugger contains the number of threads, the id of each of these threads  
and which one is the current thread.

Added a threads command to the developer shell debugger for showing  
information on threads.
Review URL: http://codereview.chromium.org/48009

Modified: branches/bleeding_edge/src/d8.js
==============================================================================
--- branches/bleeding_edge/src/d8.js    (original)
+++ branches/bleeding_edge/src/d8.js    Tue Mar 17 04:40:47 2009
@@ -324,6 +324,10 @@
        this.request_ = this.clearCommandToJSONRequest_(args);
        break;

+    case 'threads':
+      this.request_ = this.threadsCommandToJSONRequest_(args);
+      break;
+
      case 'trace':
        // Return undefined to indicate command handled internally (no JSON).
        this.request_ = void 0;
@@ -686,6 +690,14 @@
  };


+// Create a JSON request for the threads command.
+DebugRequest.prototype.threadsCommandToJSONRequest_ = function(args) {
+  // Build a threads request from the text command.
+  var request = this.createRequest('threads');
+  return request.toJSONProtocol();
+};
+
+
  // Handle the trace command.
  DebugRequest.prototype.traceCommand_ = function(args) {
    // Process arguments.
@@ -915,6 +927,18 @@
            }
            result += sourceStart;
            result += ']';
+        }
+        details.text = result;
+        break;
+
+      case 'threads':
+        var result = 'Active V8 threads: ' + body.totalThreads + '\n';
+        body.threads.sort(function(a, b) { return a.id - b.id; });
+        for (i = 0; i < body.threads.length; i++) {
+          result += body.threads[i].current ? '*' : ' ';
+          result += ' ';
+          result += body.threads[i].id;
+          result += '\n';
          }
          details.text = result;
          break;

Modified: branches/bleeding_edge/src/debug-delay.js
==============================================================================
--- branches/bleeding_edge/src/debug-delay.js   (original)
+++ branches/bleeding_edge/src/debug-delay.js   Tue Mar 17 04:40:47 2009
@@ -752,6 +752,10 @@
    return %GetFrameCount(this.break_id);
  };

+ExecutionState.prototype.threadCount = function() {
+  return %GetThreadCount(this.break_id);
+};
+
  ExecutionState.prototype.frame = function(opt_index) {
    // If no index supplied return the selected frame.
    if (opt_index == null) opt_index = this.selected_frame;
@@ -1167,6 +1171,8 @@
          this.sourceRequest_(request, response);
        } else if (request.command == 'scripts') {
          this.scriptsRequest_(request, response);
+      } else if (request.command == 'threads') {
+        this.threadsRequest_(request, response);
        } else {
          throw new Error('Unknown command "' + request.command + '" in  
request');
        }
@@ -1669,6 +1675,28 @@
        script.type = scripts[i].type;
        response.body.push(script);
      }
+  }
+};
+
+
+DebugCommandProcessor.prototype.threadsRequest_ = function(request,  
response) {
+  // Get the number of threads.
+  var total_threads = this.exec_state_.threadCount();
+
+  // Get information for all threads.
+  var threads = [];
+  for (var i = 0; i < total_threads; i++) {
+    var details = %GetThreadDetails(this.exec_state_.break_id, i);
+    var thread_info = { current: details[0],
+                        id: details[1]
+                      }
+    threads.push(thread_info);
+  }
+
+  // Create the response body.
+  response.body = {
+    totalThreads: total_threads,
+    threads: threads
    }
  };


Modified: branches/bleeding_edge/src/runtime.cc
==============================================================================
--- branches/bleeding_edge/src/runtime.cc       (original)
+++ branches/bleeding_edge/src/runtime.cc       Tue Mar 17 04:40:47 2009
@@ -5738,6 +5738,78 @@
  }


+static Object* Runtime_GetThreadCount(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 1);
+
+  // Check arguments.
+  Object* result = Runtime_CheckExecutionState(args);
+  if (result->IsFailure()) return result;
+
+  // Count all archived V8 threads.
+  int n = 0;
+  for (ThreadState* thread = ThreadState::FirstInUse();
+       thread != NULL;
+       thread = thread->Next()) {
+    n++;
+  }
+
+  // Total number of threads is current thread and archived threads.
+  return Smi::FromInt(n + 1);
+}
+
+
+static const int kThreadDetailsCurrentThreadIndex = 0;
+static const int kThreadDetailsThreadIdIndex = 1;
+static const int kThreadDetailsSize = 2;
+
+// Return an array with thread details
+// args[0]: number: break id
+// args[1]: number: thread index
+//
+// The array returned contains the following information:
+// 0: Is current thread?
+// 1: Thread id
+static Object* Runtime_GetThreadDetails(Arguments args) {
+  HandleScope scope;
+  ASSERT(args.length() == 2);
+
+  // Check arguments.
+  Object* check = Runtime_CheckExecutionState(args);
+  if (check->IsFailure()) return check;
+  CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
+
+  // Allocate array for result.
+  Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
+
+  // Thread index 0 is current thread.
+  if (index == 0) {
+    // Fill the details.
+    details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
+    details->set(kThreadDetailsThreadIdIndex,
+                 Smi::FromInt(ThreadManager::CurrentId()));
+  } else {
+    // Find the thread with the requested index.
+    int n = 1;
+    ThreadState* thread = ThreadState::FirstInUse();
+    while (index != n && thread != NULL) {
+      thread = thread->Next();
+      n++;
+    }
+    if (thread == NULL) {
+      return Heap::undefined_value();
+    }
+
+    // Fill the details.
+    details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
+    details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
+  }
+
+  // Convert to JS array and return.
+  return *Factory::NewJSArrayWithElements(details);
+}
+
+
  static Object* Runtime_GetBreakLocations(Arguments args) {
    HandleScope scope;
    ASSERT(args.length() == 1);

Modified: branches/bleeding_edge/src/runtime.h
==============================================================================
--- branches/bleeding_edge/src/runtime.h        (original)
+++ branches/bleeding_edge/src/runtime.h        Tue Mar 17 04:40:47 2009
@@ -234,6 +234,8 @@
    F(GetFrameCount, 1) \
    F(GetFrameDetails, 2) \
    F(GetCFrames, 1) \
+  F(GetThreadCount, 1) \
+  F(GetThreadDetails, 2) \
    F(GetBreakLocations, 1) \
    F(SetFunctionBreakPoint, 3) \
    F(SetScriptBreakPoint, 3) \

Modified: branches/bleeding_edge/src/v8threads.cc
==============================================================================
--- branches/bleeding_edge/src/v8threads.cc     (original)
+++ branches/bleeding_edge/src/v8threads.cc     Tue Mar 17 04:40:47 2009
@@ -38,6 +38,8 @@

  static internal::Thread::LocalStorageKey thread_state_key =
      internal::Thread::CreateThreadLocalKey();
+static internal::Thread::LocalStorageKey thread_id_key =
+    internal::Thread::CreateThreadLocalKey();


  // Track whether this V8 instance has ever called v8::Locker. This allows  
the
@@ -61,6 +63,9 @@
      }
    }
    ASSERT(internal::ThreadManager::IsLockedByCurrentThread());
+
+  // Make sure this thread is assigned a thread id.
+  internal::ThreadManager::AssignId();
  }


@@ -115,6 +120,7 @@
      lazily_archived_thread_.Initialize(ThreadHandle::INVALID);
      ASSERT(Thread::GetThreadLocal(thread_state_key) ==
             lazily_archived_thread_state_);
+    lazily_archived_thread_state_->set_id(kInvalidId);
      lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
      lazily_archived_thread_state_ = NULL;
      Thread::SetThreadLocal(thread_state_key, NULL);
@@ -143,6 +149,7 @@
    from = RegExpStack::RestoreStack(from);
    from = Bootstrapper::RestoreState(from);
    Thread::SetThreadLocal(thread_state_key, NULL);
+  state->set_id(kInvalidId);
    state->Unlink();
    state->LinkInto(ThreadState::FREE_LIST);
    return true;
@@ -176,7 +183,8 @@
  ThreadState* ThreadState::in_use_anchor_ = new ThreadState();


-ThreadState::ThreadState() : next_(this), previous_(this) {
+ThreadState::ThreadState() : id_(ThreadManager::kInvalidId),
+                             next_(this), previous_(this) {
  }


@@ -224,6 +232,7 @@
  }


+int ThreadManager::next_id_ = 0;
  Mutex* ThreadManager::mutex_ = OS::CreateMutex();
  ThreadHandle ThreadManager::mutex_owner_(ThreadHandle::INVALID);
  ThreadHandle ThreadManager::lazily_archived_thread_(ThreadHandle::INVALID);
@@ -238,6 +247,9 @@
    Thread::SetThreadLocal(thread_state_key, reinterpret_cast<void*>(state));
    lazily_archived_thread_.Initialize(ThreadHandle::SELF);
    lazily_archived_thread_state_ = state;
+  ASSERT(state->id() == kInvalidId);
+  state->set_id(CurrentId());
+  ASSERT(state->id() != kInvalidId);
  }


@@ -286,6 +298,18 @@
      char* data = state->data();
      data += HandleScopeImplementer::ArchiveSpacePerThread();
      Top::MarkCompactEpilogue(is_compacting, data);
+  }
+}
+
+
+int ThreadManager::CurrentId() {
+  return bit_cast<int, void*>(Thread::GetThreadLocal(thread_id_key));
+}
+
+
+void ThreadManager::AssignId() {
+  if (Thread::GetThreadLocal(thread_id_key) == NULL) {
+    Thread::SetThreadLocal(thread_id_key, bit_cast<void*,  
int>(next_id_++));
    }
  }


Modified: branches/bleeding_edge/src/v8threads.h
==============================================================================
--- branches/bleeding_edge/src/v8threads.h      (original)
+++ branches/bleeding_edge/src/v8threads.h      Tue Mar 17 04:40:47 2009
@@ -45,6 +45,10 @@

    static ThreadState* GetFree();

+  // Id of thread.
+  void set_id(int id) { id_ = id; }
+  int id() { return id_; }
+
    // Get data area for archiving a thread.
    char* data() { return data_; }
   private:
@@ -52,9 +56,11 @@

    void AllocateSpace();

+  int id_;
    char* data_;
    ThreadState* next_;
    ThreadState* previous_;
+
    // In the following two lists there is always at least one object on the  
list.
    // The first object is a flying anchor that is only there to simplify  
linking
    // and unlinking.
@@ -77,9 +83,15 @@
    static void MarkCompactPrologue(bool is_compacting);
    static void MarkCompactEpilogue(bool is_compacting);
    static bool IsLockedByCurrentThread() { return mutex_owner_.IsSelf(); }
+
+  static int CurrentId();
+  static void AssignId();
+
+  static const int kInvalidId = -1;
   private:
    static void EagerlyArchiveThread();

+  static int next_id_;  // V8 threads are identified through an integer.
    static Mutex* mutex_;
    static ThreadHandle mutex_owner_;
    static ThreadHandle lazily_archived_thread_;

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to