PthreadMocks.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. /*
  2. * Copyright 2008, Yahoo! Inc.
  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. #ifndef PTHREADMOCKS_H_
  17. #define PTHREADMOCKS_H_
  18. #include <pthread.h>
  19. #include <string.h>
  20. #include <errno.h>
  21. #include "src/zk_adaptor.h"
  22. #include "Util.h"
  23. #include "MocksBase.h"
  24. #include "LibCSymTable.h"
  25. #include "ThreadingUtil.h"
  26. // an ABC for pthreads
  27. class MockPthreadsBase: public Mock
  28. {
  29. public:
  30. MockPthreadsBase(){mock_=this;}
  31. virtual ~MockPthreadsBase(){mock_=0;}
  32. virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,
  33. void *(*f)(void *), void *d) =0;
  34. virtual int pthread_join(pthread_t t, void ** r) =0;
  35. virtual int pthread_detach(pthread_t t) =0;
  36. virtual int pthread_cond_broadcast(pthread_cond_t *c) =0;
  37. virtual int pthread_cond_destroy(pthread_cond_t *c) =0;
  38. virtual int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a) =0;
  39. virtual int pthread_cond_signal(pthread_cond_t *c) =0;
  40. virtual int pthread_cond_timedwait(pthread_cond_t *c,
  41. pthread_mutex_t *m, const struct timespec *t) =0;
  42. virtual int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m) =0;
  43. virtual int pthread_mutex_destroy(pthread_mutex_t *m) =0;
  44. virtual int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a) =0;
  45. virtual int pthread_mutex_lock(pthread_mutex_t *m) =0;
  46. virtual int pthread_mutex_trylock(pthread_mutex_t *m) =0;
  47. virtual int pthread_mutex_unlock(pthread_mutex_t *m) =0;
  48. static MockPthreadsBase* mock_;
  49. };
  50. // all pthread functions simply return an error code
  51. // and increment their invocation counter. No actual threads are spawned.
  52. class MockPthreadsNull: public MockPthreadsBase
  53. {
  54. public:
  55. MockPthreadsNull():
  56. pthread_createReturns(0),pthread_createCounter(0),
  57. pthread_joinReturns(0),pthread_joinCounter(0),pthread_joinResultReturn(0),
  58. pthread_detachReturns(0),pthread_detachCounter(0),
  59. pthread_cond_broadcastReturns(0),pthread_cond_broadcastCounter(0),
  60. pthread_cond_destroyReturns(0),pthread_cond_destroyCounter(0),
  61. pthread_cond_initReturns(0),pthread_cond_initCounter(0),
  62. pthread_cond_signalReturns(0),pthread_cond_signalCounter(0),
  63. pthread_cond_timedwaitReturns(0),pthread_cond_timedwaitCounter(0),
  64. pthread_cond_waitReturns(0),pthread_cond_waitCounter(0),
  65. pthread_mutex_destroyReturns(0),pthread_mutex_destroyCounter(0),
  66. pthread_mutex_initReturns(0),pthread_mutex_initCounter(0),
  67. pthread_mutex_lockReturns(0),pthread_mutex_lockCounter(0),
  68. pthread_mutex_trylockReturns(0),pthread_mutex_trylockCounter(0),
  69. pthread_mutex_unlockReturns(0),pthread_mutex_unlockCounter(0)
  70. {
  71. memset(threads,0,sizeof(threads));
  72. }
  73. short threads[512];
  74. int pthread_createReturns;
  75. int pthread_createCounter;
  76. virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,
  77. void *(*f)(void *), void *d){
  78. char* p=(char*)&threads[pthread_createCounter++];
  79. p[0]='i'; // mark as created
  80. *t=(pthread_t)p;
  81. return pthread_createReturns;
  82. }
  83. int pthread_joinReturns;
  84. int pthread_joinCounter;
  85. void* pthread_joinResultReturn;
  86. virtual int pthread_join(pthread_t t, void ** r){
  87. pthread_joinCounter++;
  88. if(r!=0)
  89. *r=pthread_joinResultReturn;
  90. char* p=(char*)t;
  91. p[0]='x';p[1]+=1;
  92. return pthread_joinReturns;
  93. }
  94. int pthread_detachReturns;
  95. int pthread_detachCounter;
  96. virtual int pthread_detach(pthread_t t){
  97. pthread_detachCounter++;
  98. char* p=(char*)t;
  99. p[0]='x';p[1]+=1;
  100. return pthread_detachReturns;
  101. }
  102. template<class T>
  103. static bool isInitialized(const T& t){
  104. return ((char*)t)[0]=='i';
  105. }
  106. template<class T>
  107. static bool isDestroyed(const T& t){
  108. return ((char*)t)[0]=='x';
  109. }
  110. template<class T>
  111. static int getDestroyCounter(const T& t){
  112. return ((char*)t)[1];
  113. }
  114. template<class T>
  115. static int getInvalidAccessCounter(const T& t){
  116. return ((char*)t)[2];
  117. }
  118. int pthread_cond_broadcastReturns;
  119. int pthread_cond_broadcastCounter;
  120. virtual int pthread_cond_broadcast(pthread_cond_t *c){
  121. pthread_cond_broadcastCounter++;
  122. if(isDestroyed(c))((char*)c)[2]++;
  123. return pthread_cond_broadcastReturns;
  124. }
  125. int pthread_cond_destroyReturns;
  126. int pthread_cond_destroyCounter;
  127. virtual int pthread_cond_destroy(pthread_cond_t *c){
  128. pthread_cond_destroyCounter++;
  129. char* p=(char*)c;
  130. p[0]='x';p[1]+=1;
  131. return pthread_cond_destroyReturns;
  132. }
  133. int pthread_cond_initReturns;
  134. int pthread_cond_initCounter;
  135. virtual int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a){
  136. pthread_cond_initCounter++;
  137. char* p=(char*)c;
  138. p[0]='i'; // mark as created
  139. p[1]=0; // destruction counter
  140. p[2]=0; // access after destruction counter
  141. return pthread_cond_initReturns;
  142. }
  143. int pthread_cond_signalReturns;
  144. int pthread_cond_signalCounter;
  145. virtual int pthread_cond_signal(pthread_cond_t *c){
  146. pthread_cond_signalCounter++;
  147. if(isDestroyed(c))((char*)c)[2]++;
  148. return pthread_cond_signalReturns;
  149. }
  150. int pthread_cond_timedwaitReturns;
  151. int pthread_cond_timedwaitCounter;
  152. virtual int pthread_cond_timedwait(pthread_cond_t *c,
  153. pthread_mutex_t *m, const struct timespec *t){
  154. pthread_cond_timedwaitCounter++;
  155. if(isDestroyed(c))((char*)c)[2]++;
  156. return pthread_cond_timedwaitReturns;
  157. }
  158. int pthread_cond_waitReturns;
  159. int pthread_cond_waitCounter;
  160. virtual int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m){
  161. pthread_cond_waitCounter++;
  162. if(isDestroyed(c))((char*)c)[2]++;
  163. return pthread_cond_waitReturns;
  164. }
  165. int pthread_mutex_destroyReturns;
  166. int pthread_mutex_destroyCounter;
  167. virtual int pthread_mutex_destroy(pthread_mutex_t *m){
  168. pthread_mutex_destroyCounter++;
  169. char* p=(char*)m;
  170. p[0]='x';p[1]+=1;
  171. return pthread_mutex_destroyReturns;
  172. }
  173. int pthread_mutex_initReturns;
  174. int pthread_mutex_initCounter;
  175. virtual int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a){
  176. pthread_mutex_initCounter++;
  177. char* p=(char*)m;
  178. p[0]='i'; // mark as created
  179. p[1]=0; // destruction counter
  180. p[2]=0; // access after destruction counter
  181. return pthread_mutex_initReturns;
  182. }
  183. int pthread_mutex_lockReturns;
  184. int pthread_mutex_lockCounter;
  185. virtual int pthread_mutex_lock(pthread_mutex_t *m){
  186. pthread_mutex_lockCounter++;
  187. if(isDestroyed(m))((char*)m)[2]++;
  188. return pthread_mutex_lockReturns;
  189. }
  190. int pthread_mutex_trylockReturns;
  191. int pthread_mutex_trylockCounter;
  192. virtual int pthread_mutex_trylock(pthread_mutex_t *m){
  193. pthread_mutex_trylockCounter++;
  194. if(isDestroyed(m))((char*)m)[2]++;
  195. return pthread_mutex_trylockReturns;
  196. }
  197. int pthread_mutex_unlockReturns;
  198. int pthread_mutex_unlockCounter;
  199. virtual int pthread_mutex_unlock(pthread_mutex_t *m){
  200. pthread_mutex_unlockCounter++;
  201. if(isDestroyed(m))((char*)m)[2]++;
  202. return pthread_mutex_unlockReturns;
  203. }
  204. };
  205. // simulates the way zookeeper threads make use of api_prolog/epilog and
  206. //
  207. class MockPthreadZKNull: public MockPthreadsNull
  208. {
  209. typedef std::map<pthread_t,zhandle_t*> Map;
  210. Map map_;
  211. public:
  212. virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,
  213. void *(*f)(void *), void *d){
  214. int ret=MockPthreadsNull::pthread_create(t,a,f,d);
  215. zhandle_t* zh=(zhandle_t*)d;
  216. adaptor_threads* ad=(adaptor_threads*)zh->adaptor_priv;
  217. api_prolog(zh);
  218. ad->threadsToWait--;
  219. putValue(map_,*t,zh);
  220. return ret;
  221. }
  222. virtual int pthread_join(pthread_t t, void ** r){
  223. zhandle_t* zh=0;
  224. if(getValue(map_,t,zh))
  225. api_epilog(zh,0);
  226. return MockPthreadsNull::pthread_join(t,r);
  227. }
  228. };
  229. struct ThreadInfo{
  230. typedef enum {RUNNING,TERMINATED} ThreadState;
  231. ThreadInfo():
  232. destructionCounter_(0),invalidAccessCounter_(0),state_(RUNNING)
  233. {
  234. }
  235. ThreadInfo& incDestroyed() {
  236. destructionCounter_++;
  237. return *this;
  238. }
  239. ThreadInfo& incInvalidAccess(){
  240. invalidAccessCounter_++;
  241. return *this;
  242. }
  243. ThreadInfo& setTerminated(){
  244. state_=TERMINATED;
  245. return *this;
  246. }
  247. int destructionCounter_;
  248. int invalidAccessCounter_;
  249. ThreadState state_;
  250. };
  251. class CheckedPthread: public MockPthreadsBase
  252. {
  253. // first => destruction counter
  254. // second => invalid access counter
  255. //typedef std::pair<int,int> Entry;
  256. typedef ThreadInfo Entry;
  257. typedef std::map<pthread_t,Entry> ThreadMap;
  258. static ThreadMap tmap_;
  259. static ThreadMap& getMap(const TypeOp<pthread_t>::BareT&){return tmap_;}
  260. typedef std::map<pthread_mutex_t*,Entry> MutexMap;
  261. static MutexMap mmap_;
  262. static MutexMap& getMap(const TypeOp<pthread_mutex_t>::BareT&){return mmap_;}
  263. typedef std::map<pthread_cond_t*,Entry> CVMap;
  264. static CVMap cvmap_;
  265. static CVMap& getMap(const TypeOp<pthread_cond_t>::BareT&){return cvmap_;}
  266. static Mutex mx;
  267. template<class T>
  268. static void markDestroyed(T& t){
  269. typedef typename TypeOp<T>::BareT Type;
  270. Entry e;
  271. synchronized(mx);
  272. if(getValue(getMap(Type()),t,e)){
  273. putValue(getMap(Type()),t,Entry(e).incDestroyed());
  274. }else{
  275. putValue(getMap(Type()),t,Entry().incDestroyed());
  276. }
  277. }
  278. template<class T>
  279. static void markCreated(T& t){
  280. typedef typename TypeOp<T>::BareT Type;
  281. Entry e;
  282. synchronized(mx);
  283. if(!getValue(getMap(Type()),t,e))
  284. putValue(getMap(Type()),t,Entry());
  285. }
  286. template<class T>
  287. static void checkAccessed(T& t){
  288. typedef typename TypeOp<T>::BareT Type;
  289. Entry e;
  290. synchronized(mx);
  291. if(getValue(getMap(Type()),t,e) && e.destructionCounter_>0)
  292. putValue(getMap(Type()),t,Entry(e).incInvalidAccess());
  293. }
  294. static void setTerminated(pthread_t t){
  295. Entry e;
  296. synchronized(mx);
  297. if(getValue(tmap_,t,e))
  298. putValue(tmap_,t,Entry(e).setTerminated());
  299. }
  300. public:
  301. bool verbose;
  302. CheckedPthread():verbose(false){
  303. tmap_.clear();
  304. mmap_.clear();
  305. cvmap_.clear();
  306. mx.release();
  307. }
  308. template <class T>
  309. static bool isInitialized(const T& t){
  310. typedef typename TypeOp<T>::BareT Type;
  311. Entry e;
  312. synchronized(mx);
  313. return getValue(getMap(Type()),t,e) && e.destructionCounter_==0;
  314. }
  315. template <class T>
  316. static bool isDestroyed(const T& t){
  317. typedef typename TypeOp<T>::BareT Type;
  318. Entry e;
  319. synchronized(mx);
  320. return getValue(getMap(Type()),t,e) && e.destructionCounter_>0;
  321. }
  322. static bool isTerminated(pthread_t t){
  323. Entry e;
  324. synchronized(mx);
  325. return getValue(tmap_,t,e) && e.state_==ThreadInfo::TERMINATED;
  326. }
  327. template <class T>
  328. static int getDestroyCounter(const T& t){
  329. typedef typename TypeOp<T>::BareT Type;
  330. Entry e;
  331. synchronized(mx);
  332. return getValue(getMap(Type()),t,e)?e.destructionCounter_:-1;
  333. }
  334. template<class T>
  335. static int getInvalidAccessCounter(const T& t){
  336. typedef typename TypeOp<T>::BareT Type;
  337. Entry e;
  338. synchronized(mx);
  339. return getValue(getMap(Type()),t,e)?e.invalidAccessCounter_:-1;
  340. }
  341. struct ThreadContext{
  342. typedef void *(*ThreadFunc)(void *);
  343. ThreadContext(ThreadFunc func,void* param):func_(func),param_(param){}
  344. ThreadFunc func_;
  345. void* param_;
  346. };
  347. static void* threadFuncWrapper(void* v){
  348. ThreadContext* ctx=(ThreadContext*)v;
  349. pthread_t t=pthread_self();
  350. markCreated(t);
  351. void* res=ctx->func_(ctx->param_);
  352. setTerminated(pthread_self());
  353. delete ctx;
  354. return res;
  355. }
  356. virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,
  357. void *(*f)(void *), void *d)
  358. {
  359. int ret=LIBC_SYMBOLS.pthread_create(t,a,threadFuncWrapper,
  360. new ThreadContext(f,d));
  361. if(verbose)
  362. TEST_TRACE(("thread created %p",*t));
  363. return ret;
  364. }
  365. virtual int pthread_join(pthread_t t, void ** r){
  366. if(verbose) TEST_TRACE(("thread joined %p",t));
  367. int ret=LIBC_SYMBOLS.pthread_join(t,r);
  368. if(ret==0)
  369. markDestroyed(t);
  370. return ret;
  371. }
  372. virtual int pthread_detach(pthread_t t){
  373. if(verbose) TEST_TRACE(("thread detached %p",t));
  374. int ret=LIBC_SYMBOLS.pthread_detach(t);
  375. if(ret==0)
  376. markDestroyed(t);
  377. return ret;
  378. }
  379. virtual int pthread_cond_broadcast(pthread_cond_t *c){
  380. checkAccessed(c);
  381. return LIBC_SYMBOLS.pthread_cond_broadcast(c);
  382. }
  383. virtual int pthread_cond_destroy(pthread_cond_t *c){
  384. markDestroyed(c);
  385. return LIBC_SYMBOLS.pthread_cond_destroy(c);
  386. }
  387. virtual int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a){
  388. markCreated(c);
  389. return LIBC_SYMBOLS.pthread_cond_init(c,a);
  390. }
  391. virtual int pthread_cond_signal(pthread_cond_t *c){
  392. checkAccessed(c);
  393. return LIBC_SYMBOLS.pthread_cond_signal(c);
  394. }
  395. virtual int pthread_cond_timedwait(pthread_cond_t *c,
  396. pthread_mutex_t *m, const struct timespec *t){
  397. checkAccessed(c);
  398. return LIBC_SYMBOLS.pthread_cond_timedwait(c,m,t);
  399. }
  400. virtual int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m){
  401. checkAccessed(c);
  402. return LIBC_SYMBOLS.pthread_cond_wait(c,m);
  403. }
  404. virtual int pthread_mutex_destroy(pthread_mutex_t *m){
  405. markDestroyed(m);
  406. return LIBC_SYMBOLS.pthread_mutex_destroy(m);
  407. }
  408. virtual int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a){
  409. markCreated(m);
  410. return LIBC_SYMBOLS.pthread_mutex_init(m,a);
  411. }
  412. virtual int pthread_mutex_lock(pthread_mutex_t *m){
  413. checkAccessed(m);
  414. return LIBC_SYMBOLS.pthread_mutex_lock(m);
  415. }
  416. virtual int pthread_mutex_trylock(pthread_mutex_t *m){
  417. checkAccessed(m);
  418. return LIBC_SYMBOLS.pthread_mutex_trylock(m);
  419. }
  420. virtual int pthread_mutex_unlock(pthread_mutex_t *m){
  421. checkAccessed(m);
  422. return LIBC_SYMBOLS.pthread_mutex_unlock(m);
  423. }
  424. };
  425. #endif /*PTHREADMOCKS_H_*/