PthreadMocks.h 15 KB

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