atom_bindings.cc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // Copyright (c) 2013 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "atom/common/api/atom_bindings.h"
  5. #include <algorithm>
  6. #include <iostream>
  7. #include <string>
  8. #include "atom/common/atom_version.h"
  9. #include "atom/common/chrome_version.h"
  10. #include "atom/common/native_mate_converters/string16_converter.h"
  11. #include "atom/common/node_includes.h"
  12. #include "base/logging.h"
  13. #include "base/process/process_metrics.h"
  14. #include "native_mate/dictionary.h"
  15. namespace atom {
  16. namespace {
  17. // Dummy class type that used for crashing the program.
  18. struct DummyClass { bool crash; };
  19. void Hang() {
  20. for (;;)
  21. base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
  22. }
  23. v8::Local<v8::Value> GetProcessMemoryInfo(v8::Isolate* isolate) {
  24. std::unique_ptr<base::ProcessMetrics> metrics(
  25. base::ProcessMetrics::CreateCurrentProcessMetrics());
  26. mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
  27. dict.Set("workingSetSize",
  28. static_cast<double>(metrics->GetWorkingSetSize() >> 10));
  29. dict.Set("peakWorkingSetSize",
  30. static_cast<double>(metrics->GetPeakWorkingSetSize() >> 10));
  31. size_t private_bytes, shared_bytes;
  32. if (metrics->GetMemoryBytes(&private_bytes, &shared_bytes)) {
  33. dict.Set("privateBytes", static_cast<double>(private_bytes >> 10));
  34. dict.Set("sharedBytes", static_cast<double>(shared_bytes >> 10));
  35. }
  36. return dict.GetHandle();
  37. }
  38. v8::Local<v8::Value> GetSystemMemoryInfo(v8::Isolate* isolate,
  39. mate::Arguments* args) {
  40. base::SystemMemoryInfoKB mem_info;
  41. if (!base::GetSystemMemoryInfo(&mem_info)) {
  42. args->ThrowError("Unable to retrieve system memory information");
  43. return v8::Undefined(isolate);
  44. }
  45. mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
  46. dict.Set("total", mem_info.total);
  47. dict.Set("free", mem_info.free);
  48. // NB: These return bogus values on macOS
  49. #if !defined(OS_MACOSX)
  50. dict.Set("swapTotal", mem_info.swap_total);
  51. dict.Set("swapFree", mem_info.swap_free);
  52. #endif
  53. return dict.GetHandle();
  54. }
  55. // Called when there is a fatal error in V8, we just crash the process here so
  56. // we can get the stack trace.
  57. void FatalErrorCallback(const char* location, const char* message) {
  58. LOG(ERROR) << "Fatal error in V8: " << location << " " << message;
  59. AtomBindings::Crash();
  60. }
  61. } // namespace
  62. AtomBindings::AtomBindings() {
  63. uv_async_init(uv_default_loop(), &call_next_tick_async_, OnCallNextTick);
  64. call_next_tick_async_.data = this;
  65. }
  66. AtomBindings::~AtomBindings() {
  67. }
  68. void AtomBindings::BindTo(v8::Isolate* isolate,
  69. v8::Local<v8::Object> process) {
  70. v8::V8::SetFatalErrorHandler(FatalErrorCallback);
  71. mate::Dictionary dict(isolate, process);
  72. dict.SetMethod("crash", &AtomBindings::Crash);
  73. dict.SetMethod("hang", &Hang);
  74. dict.SetMethod("log", &Log);
  75. dict.SetMethod("getProcessMemoryInfo", &GetProcessMemoryInfo);
  76. dict.SetMethod("getSystemMemoryInfo", &GetSystemMemoryInfo);
  77. #if defined(OS_POSIX)
  78. dict.SetMethod("setFdLimit", &base::SetFdLimit);
  79. #endif
  80. dict.SetMethod("activateUvLoop",
  81. base::Bind(&AtomBindings::ActivateUVLoop, base::Unretained(this)));
  82. #if defined(MAS_BUILD)
  83. dict.Set("mas", true);
  84. #endif
  85. mate::Dictionary versions;
  86. if (dict.Get("versions", &versions)) {
  87. // TODO(kevinsawicki): Make read-only in 2.0 to match node
  88. versions.Set(ATOM_PROJECT_NAME, ATOM_VERSION_STRING);
  89. versions.Set("chrome", CHROME_VERSION_STRING);
  90. // TODO(kevinsawicki): Remove in 2.0
  91. versions.Set("atom-shell", ATOM_VERSION_STRING);
  92. }
  93. }
  94. void AtomBindings::ActivateUVLoop(v8::Isolate* isolate) {
  95. node::Environment* env = node::Environment::GetCurrent(isolate);
  96. if (std::find(pending_next_ticks_.begin(), pending_next_ticks_.end(), env) !=
  97. pending_next_ticks_.end())
  98. return;
  99. pending_next_ticks_.push_back(env);
  100. uv_async_send(&call_next_tick_async_);
  101. }
  102. // static
  103. void AtomBindings::OnCallNextTick(uv_async_t* handle) {
  104. AtomBindings* self = static_cast<AtomBindings*>(handle->data);
  105. for (std::list<node::Environment*>::const_iterator it =
  106. self->pending_next_ticks_.begin();
  107. it != self->pending_next_ticks_.end(); ++it) {
  108. node::Environment* env = *it;
  109. // KickNextTick, copied from node.cc:
  110. node::Environment::AsyncCallbackScope callback_scope(env);
  111. if (callback_scope.in_makecallback())
  112. continue;
  113. node::Environment::TickInfo* tick_info = env->tick_info();
  114. if (tick_info->length() == 0)
  115. env->isolate()->RunMicrotasks();
  116. v8::Local<v8::Object> process = env->process_object();
  117. if (tick_info->length() == 0)
  118. tick_info->set_index(0);
  119. env->tick_callback_function()->Call(process, 0, nullptr).IsEmpty();
  120. }
  121. self->pending_next_ticks_.clear();
  122. }
  123. // static
  124. void AtomBindings::Log(const base::string16& message) {
  125. std::cout << message << std::flush;
  126. }
  127. // static
  128. void AtomBindings::Crash() {
  129. static_cast<DummyClass*>(nullptr)->crash = true;
  130. }
  131. } // namespace atom