ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

206 lines
5.1 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
  4. //
  5. // See accompanying file COPYING.TXT file for licensing details.
  6. //
  7. ///////////////////////////////////////////////////////////////////////////////
  8. #ifndef CPPCMS_IMPL_PREFORK_ACCEPTOR_H
  9. #define CPPCMS_IMPL_PREFORK_ACCEPTOR_H
  10. #include <cppcms/service.h>
  11. #include <booster/thread.h>
  12. #include <booster/noncopyable.h>
  13. #include <booster/aio/socket.h>
  14. #include <booster/system_error.h>
  15. #include <booster/log.h>
  16. #include <sys/time.h>
  17. #include <sys/types.h>
  18. #include <unistd.h>
  19. #include <sys/socket.h>
  20. #include <algorithm>
  21. #include <booster/auto_ptr_inc.h>
  22. #include "cgi_api.h"
  23. #include <cppcms/mem_bind.h>
  24. namespace cppcms {
  25. namespace impl {
  26. class prefork_acceptor : public booster::noncopyable {
  27. public:
  28. prefork_acceptor(cppcms::service *srv)
  29. {
  30. service_ = srv;
  31. stop_ = false;
  32. read_interrupter_=-1;
  33. write_interrupter_=-1;
  34. }
  35. void add_acceptor(booster::shared_ptr<cgi::acceptor> acc)
  36. {
  37. acceptors_.push_back(acc);
  38. }
  39. ~prefork_acceptor()
  40. {
  41. if(thread_.get()) {
  42. if(!stop_)
  43. stop();
  44. thread_->join();
  45. thread_.reset();
  46. }
  47. if(read_interrupter_!=-1)
  48. ::close(read_interrupter_);
  49. if(write_interrupter_!=-1)
  50. ::close(write_interrupter_);
  51. }
  52. void start()
  53. {
  54. int fds[2];
  55. if(::pipe(fds) < 0) {
  56. service_->shutdown();
  57. throw booster::system::system_error(
  58. booster::system::error_code(errno,booster::system::system_category));
  59. }
  60. read_interrupter_=fds[0];
  61. write_interrupter_=fds[1];
  62. thread_.reset(new booster::thread(cppcms::util::mem_bind(&prefork_acceptor::run,this)));
  63. }
  64. private:
  65. void stop()
  66. {
  67. stop_ = true;
  68. int res = -1;
  69. do {
  70. res = ::write(write_interrupter_,"A",1);
  71. } while(res < 0 && errno==EINTR);
  72. }
  73. void run()
  74. {
  75. typedef booster::shared_ptr< cppcms::http::context> context_ptr;
  76. fd_set lset;
  77. FD_ZERO(&lset);
  78. int max = -1;
  79. for(unsigned i=0;i<acceptors_.size();i++) {
  80. int native = acceptors_[i]->socket().native();
  81. if(native < 0) {
  82. throw cppcms_error("Invalid acceptor");
  83. }
  84. else if(native >= FD_SETSIZE) {
  85. throw cppcms_error("Socket descriptor is bigger then FD_SETSIZE");
  86. }
  87. FD_SET(native,&lset);
  88. max = std::max(native,max);
  89. }
  90. FD_SET(read_interrupter_,&lset);
  91. max = std::max(read_interrupter_,max);
  92. while(!stop_) {
  93. std::vector<context_ptr> connections_;
  94. std::vector<int> accepted_fds_(acceptors_.size(),-1);;
  95. try
  96. {
  97. // Critical section
  98. {
  99. booster::unique_lock<booster::fork_shared_mutex> l(mutex_);
  100. fd_set r=lset;
  101. int n = ::select(max+1,&r,0,0,0);
  102. if(n < 0 && errno == EINTR)
  103. continue;
  104. if(n < 0) {
  105. booster::system::error_code e(errno,booster::system::system_category);
  106. BOOSTER_CRITICAL("cppcms") << "select failed:" << e.message();
  107. service_->shutdown();
  108. return;
  109. }
  110. if(stop_)
  111. break;
  112. if(FD_ISSET(read_interrupter_,&r)) {
  113. static char buf[32];
  114. int n = ::read(read_interrupter_,buf,32);
  115. if(n < 0 && errno!=EINTR && errno!=EAGAIN) {
  116. BOOSTER_CRITICAL("cppcms") << "failed to read interrupter";
  117. break;
  118. }
  119. }
  120. for(unsigned i=0;i<acceptors_.size();i++) {
  121. int fd = acceptors_[i]->socket().native();
  122. if(!FD_ISSET(fd,&r))
  123. continue;
  124. int new_fd = ::accept(fd,0,0);
  125. if(new_fd < 0) {
  126. if( errno==EINTR
  127. || errno==EAGAIN
  128. || errno==EWOULDBLOCK
  129. || errno==ECONNABORTED
  130. || errno==EPROTO)
  131. {
  132. continue;
  133. }
  134. booster::system::error_code e(errno,booster::system::system_category);
  135. if(e.value()==EMFILE || e.value()==ENFILE) {
  136. BOOSTER_ERROR("cppcms_prefork")
  137. << "Accept failed:" << e.message();
  138. continue;
  139. }
  140. else {
  141. BOOSTER_CRITICAL("cppcms_prefork")
  142. << "Accept failed:" << e.message();
  143. service_->shutdown();
  144. throw booster::system::system_error(e);
  145. }
  146. }
  147. else {
  148. accepted_fds_[i]=new_fd;
  149. }
  150. }
  151. } // End critical section
  152. for(unsigned i=0;i<accepted_fds_.size();i++) {
  153. if(accepted_fds_[i]!=-1) {
  154. int tmp = accepted_fds_[i];
  155. accepted_fds_[i]=-1;
  156. connections_.push_back(acceptors_[i]->accept(tmp));
  157. }
  158. }
  159. }
  160. catch(...) {
  161. for(unsigned i=0;i<accepted_fds_.size();i++) {
  162. if(accepted_fds_[i]!=-1) {
  163. ::close(accepted_fds_[i]);
  164. accepted_fds_[i]=-1;
  165. }
  166. }
  167. throw;
  168. }
  169. for(unsigned i=0;i<connections_.size();i++) {
  170. service_->post(cppcms::util::mem_bind(&cppcms::http::context::run,connections_[i]));
  171. }
  172. connections_.clear();
  173. } // while loop
  174. } // run function
  175. friend struct runner;
  176. std::vector<booster::shared_ptr<cgi::acceptor> > acceptors_;
  177. int read_interrupter_,write_interrupter_;
  178. bool stop_;
  179. cppcms::service *service_;
  180. std::auto_ptr<booster::thread> thread_;
  181. booster::fork_shared_mutex mutex_;
  182. };
  183. } /// impl
  184. } /// cppcms
  185. #endif