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.
 
 
 
 
 
 

332 lines
7.0 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_POSIX_UTIL_H
  9. #define CPPCMS_POSIX_UTIL_H
  10. #include <sys/mman.h>
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #include <fcntl.h>
  14. #include <sys/types.h>
  15. #include <errno.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <pthread.h>
  19. #include <cppcms/cppcms_error.h>
  20. #include <booster/noncopyable.h>
  21. namespace cppcms {
  22. namespace impl {
  23. inline void *mmap_anonymous(size_t size)
  24. {
  25. #if defined(MAP_ANONYMOUS)
  26. void *p=::mmap(0,size,PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
  27. int err=errno;
  28. #elif defined(MAP_ANON)
  29. void *p=::mmap(0,size,PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
  30. int err=errno;
  31. #else
  32. int fd=::open("/dev/null",O_RDWR);
  33. if(fd < 0)
  34. throw cppcms_error(errno,"Failed to open /dev/null");
  35. void *p=::mmap(0,size,PROT_READ | PROT_WRITE,MAP_SHARED, fd, 0);
  36. int err=errno;
  37. ::close(fd);
  38. #endif
  39. if(p==MAP_FAILED)
  40. throw cppcms_error(err,"Failed to create shared memory");
  41. return p;
  42. }
  43. inline void create_mutex(pthread_mutex_t *m,bool pshared = false)
  44. {
  45. if(!pshared) {
  46. pthread_mutex_init(m,0);
  47. }
  48. else {
  49. #ifdef CPPCMS_HAS_THREAD_PSHARED
  50. pthread_mutexattr_t attr;
  51. pthread_mutexattr_init(&attr);
  52. try {
  53. int res;
  54. res = pthread_mutexattr_setpshared(&attr,PTHREAD_PROCESS_SHARED);
  55. if(res==0)
  56. res = pthread_mutex_init(m,&attr);
  57. if(res < 0)
  58. throw cppcms_error(errno,"Failed to create process shared mutex");
  59. pthread_mutexattr_destroy(&attr);
  60. }
  61. catch(...) {
  62. pthread_mutexattr_destroy(&attr);
  63. throw;
  64. }
  65. #else
  66. throw cppcms_error("Process shared mutex is not supported");
  67. #endif
  68. }
  69. }
  70. inline void destroy_mutex(pthread_mutex_t *m)
  71. {
  72. pthread_mutex_destroy(m);
  73. }
  74. inline void create_rwlock(pthread_rwlock_t *m,bool pshared=false)
  75. {
  76. if(!pshared) {
  77. pthread_rwlock_init(m,0);
  78. }
  79. else {
  80. #ifdef CPPCMS_HAS_THREAD_PSHARED
  81. pthread_rwlockattr_t attr;
  82. pthread_rwlockattr_init(&attr);
  83. try {
  84. int res;
  85. res = pthread_rwlockattr_setpshared(&attr,PTHREAD_PROCESS_SHARED);
  86. if(res==0)
  87. res = pthread_rwlock_init(m,&attr);
  88. if(res < 0)
  89. throw cppcms_error(errno,"Failed to create process shared mutex");
  90. pthread_rwlockattr_destroy(&attr);
  91. }
  92. catch(...) {
  93. pthread_rwlockattr_destroy(&attr);
  94. throw;
  95. }
  96. #else
  97. throw cppcms_error("Process shared mutex is not supported");
  98. #endif
  99. }
  100. }
  101. inline void destroy_rwlock(pthread_rwlock_t *m)
  102. {
  103. pthread_rwlock_destroy(m);
  104. }
  105. #ifdef CPPCMS_HAS_THREAD_PSHARED
  106. inline bool test_pthread_mutex_pshared_impl()
  107. {
  108. void *memory=mmap_anonymous(sizeof(pthread_mutex_t));
  109. bool res=false;
  110. try {
  111. create_mutex(reinterpret_cast<pthread_mutex_t *>(memory),true);
  112. destroy_mutex(reinterpret_cast<pthread_mutex_t *>(memory));
  113. res=true;
  114. }
  115. catch(cppcms_error const &e) {
  116. res= false;
  117. }
  118. ::munmap((char*)memory,sizeof(pthread_mutex_t));
  119. return res;
  120. }
  121. inline bool test_pthread_mutex_pshared()
  122. {
  123. static bool has = test_pthread_mutex_pshared_impl();
  124. return has;
  125. }
  126. #else
  127. inline bool test_pthread_mutex_pshared()
  128. {
  129. return false;
  130. }
  131. #endif
  132. class mutex : public booster::noncopyable {
  133. public:
  134. class guard;
  135. mutex() :
  136. plock_(0),
  137. flock_(0)
  138. {
  139. bool use_pthread=test_pthread_mutex_pshared();
  140. if(use_pthread) {
  141. plock_ =reinterpret_cast<pthread_mutex_t *>(mmap_anonymous(sizeof(pthread_mutex_t)));
  142. create_mutex(plock_,true);
  143. }
  144. else {
  145. plock_=&normal_;
  146. create_mutex(plock_,false);
  147. flock_=tmpfile();
  148. if(!flock_) {
  149. int err=errno;
  150. destroy_mutex(plock_);
  151. throw cppcms_error(err,"Failed to create temporary file");
  152. }
  153. }
  154. }
  155. void lock()
  156. {
  157. pthread_mutex_lock(plock_);
  158. if(flock_) {
  159. struct flock lock;
  160. memset(&lock,0,sizeof(lock));
  161. lock.l_type=F_WRLCK;
  162. lock.l_whence=SEEK_SET;
  163. while(::fcntl(fileno(flock_),F_SETLKW,&lock)!=0 && errno==EINTR)
  164. ;
  165. }
  166. }
  167. void unlock()
  168. {
  169. if(flock_) {
  170. struct flock lock;
  171. memset(&lock,0,sizeof(lock));
  172. lock.l_type=F_UNLCK;
  173. lock.l_whence=SEEK_SET;
  174. while(::fcntl(fileno(flock_),F_SETLKW,&lock)!=0 && errno==EINTR)
  175. ;
  176. }
  177. pthread_mutex_unlock(plock_);
  178. }
  179. ~mutex()
  180. {
  181. if(flock_) ::fclose(flock_);
  182. destroy_mutex(plock_);
  183. if(plock_ != &normal_)
  184. ::munmap((char*)plock_,sizeof(pthread_mutex_t));
  185. }
  186. private:
  187. pthread_mutex_t *plock_;
  188. FILE *flock_;
  189. pthread_mutex_t normal_;
  190. };
  191. class mutex::guard : public booster::noncopyable {
  192. public:
  193. guard(mutex &m) : m_(m)
  194. {
  195. m_.lock();
  196. }
  197. ~guard()
  198. {
  199. m_.unlock();
  200. }
  201. private:
  202. mutex &m_;
  203. };
  204. class shared_mutex : public booster::noncopyable {
  205. public:
  206. class shared_guard;
  207. class unique_guard;
  208. shared_mutex() :
  209. plock_(0),
  210. flock_(0)
  211. {
  212. bool use_pthread=test_pthread_mutex_pshared();
  213. if(use_pthread) {
  214. plock_ =reinterpret_cast<pthread_rwlock_t *>(mmap_anonymous(sizeof(pthread_rwlock_t)));
  215. create_rwlock(plock_,true);
  216. }
  217. else {
  218. plock_=&normal_;
  219. create_rwlock(plock_,false);
  220. flock_=tmpfile();
  221. if(!flock_) {
  222. int err=errno;
  223. destroy_rwlock(plock_);
  224. throw cppcms_error(err,"Failed to create temporary file");
  225. }
  226. }
  227. }
  228. void wrlock()
  229. {
  230. pthread_rwlock_wrlock(plock_);
  231. if(flock_) {
  232. struct flock lock;
  233. memset(&lock,0,sizeof(lock));
  234. lock.l_type=F_WRLCK;
  235. lock.l_whence=SEEK_SET;
  236. while(::fcntl(fileno(flock_),F_SETLKW,&lock)!=0 && errno==EINTR)
  237. ;
  238. }
  239. }
  240. void rdlock()
  241. {
  242. pthread_rwlock_rdlock(plock_);
  243. if(flock_) {
  244. struct flock lock;
  245. memset(&lock,0,sizeof(lock));
  246. lock.l_type=F_RDLCK;
  247. lock.l_whence=SEEK_SET;
  248. while(::fcntl(fileno(flock_),F_SETLKW,&lock)!=0 && errno==EINTR)
  249. ;
  250. }
  251. }
  252. void unlock()
  253. {
  254. if(flock_) {
  255. struct flock lock;
  256. memset(&lock,0,sizeof(lock));
  257. lock.l_type=F_UNLCK;
  258. lock.l_whence=SEEK_SET;
  259. while(::fcntl(fileno(flock_),F_SETLKW,&lock)!=0 && errno==EINTR)
  260. ;
  261. }
  262. pthread_rwlock_unlock(plock_);
  263. }
  264. ~shared_mutex()
  265. {
  266. if(flock_) ::fclose(flock_);
  267. destroy_rwlock(plock_);
  268. if(plock_ != &normal_)
  269. ::munmap((char*)plock_,sizeof(pthread_rwlock_t));
  270. }
  271. private:
  272. pthread_rwlock_t *plock_;
  273. FILE *flock_;
  274. pthread_rwlock_t normal_;
  275. };
  276. class shared_mutex::shared_guard : public booster::noncopyable {
  277. public:
  278. shared_guard(shared_mutex &m) : m_(m)
  279. {
  280. m_.rdlock();
  281. }
  282. ~shared_guard()
  283. {
  284. m_.unlock();
  285. }
  286. private:
  287. shared_mutex &m_;
  288. };
  289. class shared_mutex::unique_guard : public booster::noncopyable {
  290. public:
  291. unique_guard(shared_mutex &m) : m_(m)
  292. {
  293. m_.wrlock();
  294. }
  295. ~unique_guard()
  296. {
  297. m_.unlock();
  298. }
  299. private:
  300. shared_mutex &m_;
  301. };
  302. } // impl
  303. } // cppcms
  304. #endif