workqueue-threads.cc 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. // workqueue-threads.cc -- the threaded workqueue for gold
  2. // Copyright (C) 2007-2022 Free Software Foundation, Inc.
  3. // Written by Ian Lance Taylor <iant@google.com>.
  4. // This file is part of gold.
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation; either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program; if not, write to the Free Software
  15. // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
  16. // MA 02110-1301, USA.
  17. // This file holds the workqueue implementation which may be used when
  18. // using threads.
  19. #include "gold.h"
  20. #ifdef ENABLE_THREADS
  21. #include <cstring>
  22. #include <pthread.h>
  23. #include "debug.h"
  24. #include "gold-threads.h"
  25. #include "workqueue.h"
  26. #include "workqueue-internal.h"
  27. namespace gold
  28. {
  29. // Class Workqueue_thread represents a single thread. Creating an
  30. // instance of this spawns a new thread.
  31. class Workqueue_thread
  32. {
  33. public:
  34. Workqueue_thread(Workqueue_threader_threadpool*, int thread_number);
  35. ~Workqueue_thread();
  36. private:
  37. // This class can not be copied.
  38. Workqueue_thread(const Workqueue_thread&);
  39. Workqueue_thread& operator=(const Workqueue_thread&);
  40. // Check for error from a pthread function.
  41. void
  42. check(const char* function, int err) const;
  43. // A function to pass to pthread_create. This is called with a
  44. // pointer to an instance of this object.
  45. static void*
  46. thread_body(void*);
  47. // A pointer to the threadpool that this thread is part of.
  48. Workqueue_threader_threadpool* threadpool_;
  49. // The thread number.
  50. int thread_number_;
  51. // The thread ID.
  52. pthread_t tid_;
  53. };
  54. // Create the thread in the constructor.
  55. Workqueue_thread::Workqueue_thread(Workqueue_threader_threadpool* threadpool,
  56. int thread_number)
  57. : threadpool_(threadpool), thread_number_(thread_number)
  58. {
  59. pthread_attr_t attr;
  60. int err = pthread_attr_init(&attr);
  61. this->check("pthread_attr_init", err);
  62. err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  63. this->check("pthread_attr_setdetachstate", err);
  64. err = pthread_create(&this->tid_, &attr, &Workqueue_thread::thread_body,
  65. reinterpret_cast<void*>(this));
  66. this->check("pthread_create", err);
  67. err = pthread_attr_destroy(&attr);
  68. this->check("pthread_attr_destroy", err);
  69. }
  70. // The destructor will be called when the thread is exiting.
  71. Workqueue_thread::~Workqueue_thread()
  72. {
  73. }
  74. // Check for an error.
  75. void
  76. Workqueue_thread::check(const char* function, int err) const
  77. {
  78. if (err != 0)
  79. gold_fatal(_("%s failed: %s"), function, strerror(err));
  80. }
  81. // Passed to pthread_create.
  82. extern "C"
  83. void*
  84. Workqueue_thread::thread_body(void* arg)
  85. {
  86. Workqueue_thread* pwt = reinterpret_cast<Workqueue_thread*>(arg);
  87. pwt->threadpool_->process(pwt->thread_number_);
  88. // Delete the thread object as we exit.
  89. delete pwt;
  90. return NULL;
  91. }
  92. // Class Workqueue_threader_threadpool.
  93. // Constructor.
  94. Workqueue_threader_threadpool::Workqueue_threader_threadpool(
  95. Workqueue* workqueue)
  96. : Workqueue_threader(workqueue),
  97. check_thread_count_(0),
  98. lock_(),
  99. desired_thread_count_(1),
  100. threads_(1)
  101. {
  102. }
  103. // Destructor.
  104. Workqueue_threader_threadpool::~Workqueue_threader_threadpool()
  105. {
  106. // Tell the threads to exit.
  107. this->get_workqueue()->set_thread_count(0);
  108. }
  109. // Set the thread count.
  110. void
  111. Workqueue_threader_threadpool::set_thread_count(int thread_count)
  112. {
  113. int create;
  114. {
  115. Hold_lock hl(this->lock_);
  116. this->desired_thread_count_ = thread_count;
  117. create = this->desired_thread_count_ - this->threads_;
  118. if (create < 0)
  119. this->check_thread_count_ = 1;
  120. }
  121. if (create > 0)
  122. {
  123. for (int i = 0; i < create; ++i)
  124. {
  125. // Note that threads delete themselves when they exit, so we
  126. // don't keep pointers to them.
  127. new Workqueue_thread(this, this->threads_);
  128. ++this->threads_;
  129. }
  130. }
  131. }
  132. // Return whether the current thread should be cancelled.
  133. bool
  134. Workqueue_threader_threadpool::should_cancel_thread(int thread_number)
  135. {
  136. // Fast exit without taking a lock.
  137. if (!this->check_thread_count_)
  138. return false;
  139. {
  140. Hold_lock hl(this->lock_);
  141. if (thread_number > this->desired_thread_count_)
  142. {
  143. --this->threads_;
  144. if (this->threads_ <= this->desired_thread_count_)
  145. this->check_thread_count_ = 0;
  146. return true;
  147. }
  148. }
  149. return false;
  150. }
  151. } // End namespace gold.
  152. #endif // defined(ENABLE_THREADS)