Threads.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. * Copyright (C) 2015 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <err.h>
  17. #include <errno.h>
  18. #include <pthread.h>
  19. #include <stdint.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <sys/mman.h>
  24. #include <unistd.h>
  25. #include <new>
  26. #include "Action.h"
  27. #include "Thread.h"
  28. #include "Threads.h"
  29. void* ThreadRunner(void* data) {
  30. Thread* thread = reinterpret_cast<Thread*>(data);
  31. while (true) {
  32. thread->WaitForPending();
  33. Action* action = thread->GetAction();
  34. thread->AddTimeNsecs(action->Execute(thread->pointers()));
  35. bool end_thread = action->EndThread();
  36. thread->ClearPending();
  37. if (end_thread) {
  38. break;
  39. }
  40. }
  41. return nullptr;
  42. }
  43. Threads::Threads(Pointers* pointers, size_t max_threads)
  44. : pointers_(pointers), max_threads_(max_threads) {
  45. size_t pagesize = getpagesize();
  46. data_size_ = (max_threads_ * sizeof(Thread) + pagesize - 1) & ~(pagesize - 1);
  47. max_threads_ = data_size_ / sizeof(Thread);
  48. void* memory = mmap(nullptr, data_size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
  49. if (memory == MAP_FAILED) {
  50. err(1, "Failed to map in memory for Threads: map size %zu, max threads %zu\n",
  51. data_size_, max_threads_);
  52. }
  53. if (Thread::ACTION_SIZE < Action::MaxActionSize()) {
  54. err(1, "Thread action size is too small: ACTION_SIZE %zu, max size %zu\n",
  55. Thread::ACTION_SIZE, Action::MaxActionSize());
  56. }
  57. threads_ = new (memory) Thread[max_threads_];
  58. }
  59. Threads::~Threads() {
  60. if (threads_) {
  61. munmap(threads_, data_size_);
  62. threads_ = nullptr;
  63. data_size_ = 0;
  64. }
  65. }
  66. Thread* Threads::CreateThread(pid_t tid) {
  67. if (num_threads_ == max_threads_) {
  68. err(1, "Too many threads created, current max %zu.\n", num_threads_);
  69. }
  70. Thread* thread = FindEmptyEntry(tid);
  71. if (thread == nullptr) {
  72. err(1, "No empty entries found, current max %zu, num threads %zu\n",
  73. max_threads_, num_threads_);
  74. }
  75. thread->tid_ = tid;
  76. thread->pointers_ = pointers_;
  77. thread->total_time_nsecs_ = 0;
  78. if (pthread_create(&thread->thread_id_, nullptr, ThreadRunner, thread) == -1) {
  79. err(1, "Failed to create thread %d: %s\n", tid, strerror(errno));
  80. }
  81. num_threads_++;
  82. return thread;
  83. }
  84. Thread* Threads::FindThread(pid_t tid) {
  85. size_t index = GetHashEntry(tid);
  86. for (size_t entries = num_threads_; entries != 0; ) {
  87. pid_t cur_tid = threads_[index].tid_;
  88. if (cur_tid == tid) {
  89. return threads_ + index;
  90. }
  91. if (cur_tid != 0) {
  92. entries--;
  93. }
  94. if (++index == max_threads_) {
  95. index = 0;
  96. }
  97. }
  98. return nullptr;
  99. }
  100. void Threads::WaitForAllToQuiesce() {
  101. for (size_t i = 0, threads = 0; threads < num_threads_; i++) {
  102. pid_t cur_tid = threads_[i].tid_;
  103. if (cur_tid != 0) {
  104. threads++;
  105. threads_[i].WaitForReady();
  106. }
  107. }
  108. }
  109. size_t Threads::GetHashEntry(pid_t tid) {
  110. return tid % max_threads_;
  111. }
  112. Thread* Threads::FindEmptyEntry(pid_t tid) {
  113. size_t index = GetHashEntry(tid);
  114. for (size_t entries = 0; entries < max_threads_; entries++) {
  115. if (threads_[index].tid_ == 0) {
  116. return threads_ + index;
  117. }
  118. if (++index == max_threads_) {
  119. index = 0;
  120. }
  121. }
  122. return nullptr;
  123. }
  124. void Threads::Finish(Thread* thread) {
  125. int ret = pthread_join(thread->thread_id_, nullptr);
  126. if (ret != 0) {
  127. fprintf(stderr, "pthread_join failed: %s\n", strerror(ret));
  128. exit(1);
  129. }
  130. total_time_nsecs_ += thread->total_time_nsecs_;
  131. thread->tid_ = 0;
  132. num_threads_--;
  133. }
  134. void Threads::FinishAll() {
  135. for (size_t i = 0; i < max_threads_; i++) {
  136. if (threads_[i].tid_ != 0) {
  137. threads_[i].CreateAction(0, "thread_done", nullptr);
  138. threads_[i].SetPending();
  139. Finish(threads_ + i);
  140. }
  141. }
  142. }