123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 |
- /**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #ifndef PTHREADMOCKS_H_
- #define PTHREADMOCKS_H_
- #include <pthread.h>
- #include <string.h>
- #include <errno.h>
- #include "src/zk_adaptor.h"
- #include "Util.h"
- #include "MocksBase.h"
- #include "LibCSymTable.h"
- #include "ThreadingUtil.h"
- // an ABC for pthreads
- class MockPthreadsBase: public Mock
- {
- public:
- MockPthreadsBase(){mock_=this;}
- virtual ~MockPthreadsBase(){mock_=0;}
-
- virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,
- void *(*f)(void *), void *d) =0;
- virtual int pthread_join(pthread_t t, void ** r) =0;
- virtual int pthread_detach(pthread_t t) =0;
- virtual int pthread_cond_broadcast(pthread_cond_t *c) =0;
- virtual int pthread_cond_destroy(pthread_cond_t *c) =0;
- virtual int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a) =0;
- virtual int pthread_cond_signal(pthread_cond_t *c) =0;
- virtual int pthread_cond_timedwait(pthread_cond_t *c,
- pthread_mutex_t *m, const struct timespec *t) =0;
- virtual int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m) =0;
- virtual int pthread_mutex_destroy(pthread_mutex_t *m) =0;
- virtual int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a) =0;
- virtual int pthread_mutex_lock(pthread_mutex_t *m) =0;
- virtual int pthread_mutex_trylock(pthread_mutex_t *m) =0;
- virtual int pthread_mutex_unlock(pthread_mutex_t *m) =0;
-
- static MockPthreadsBase* mock_;
- };
- // all pthread functions simply return an error code
- // and increment their invocation counter. No actual threads are spawned.
- class MockPthreadsNull: public MockPthreadsBase
- {
- public:
- MockPthreadsNull():
- pthread_createReturns(0),pthread_createCounter(0),
- pthread_joinReturns(0),pthread_joinCounter(0),pthread_joinResultReturn(0),
- pthread_detachReturns(0),pthread_detachCounter(0),
- pthread_cond_broadcastReturns(0),pthread_cond_broadcastCounter(0),
- pthread_cond_destroyReturns(0),pthread_cond_destroyCounter(0),
- pthread_cond_initReturns(0),pthread_cond_initCounter(0),
- pthread_cond_signalReturns(0),pthread_cond_signalCounter(0),
- pthread_cond_timedwaitReturns(0),pthread_cond_timedwaitCounter(0),
- pthread_cond_waitReturns(0),pthread_cond_waitCounter(0),
- pthread_mutex_destroyReturns(0),pthread_mutex_destroyCounter(0),
- pthread_mutex_initReturns(0),pthread_mutex_initCounter(0),
- pthread_mutex_lockReturns(0),pthread_mutex_lockCounter(0),
- pthread_mutex_trylockReturns(0),pthread_mutex_trylockCounter(0),
- pthread_mutex_unlockReturns(0),pthread_mutex_unlockCounter(0)
- {
- memset(threads,0,sizeof(threads));
- }
-
- short threads[512];
-
- int pthread_createReturns;
- int pthread_createCounter;
- virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,
- void *(*f)(void *), void *d){
- char* p=(char*)&threads[pthread_createCounter++];
- p[0]='i'; // mark as created
- *t=(pthread_t)p;
- return pthread_createReturns;
- }
- int pthread_joinReturns;
- int pthread_joinCounter;
- void* pthread_joinResultReturn;
- virtual int pthread_join(pthread_t t, void ** r){
- pthread_joinCounter++;
- if(r!=0)
- *r=pthread_joinResultReturn;
- char* p=(char*)t;
- p[0]='x';p[1]+=1;
- return pthread_joinReturns;
- }
- int pthread_detachReturns;
- int pthread_detachCounter;
- virtual int pthread_detach(pthread_t t){
- pthread_detachCounter++;
- char* p=(char*)t;
- p[0]='x';p[1]+=1;
- return pthread_detachReturns;
- }
- template<class T>
- static bool isInitialized(const T& t){
- return ((char*)t)[0]=='i';
- }
- template<class T>
- static bool isDestroyed(const T& t){
- return ((char*)t)[0]=='x';
- }
- template<class T>
- static int getDestroyCounter(const T& t){
- return ((char*)t)[1];
- }
- template<class T>
- static int getInvalidAccessCounter(const T& t){
- return ((char*)t)[2];
- }
- int pthread_cond_broadcastReturns;
- int pthread_cond_broadcastCounter;
- virtual int pthread_cond_broadcast(pthread_cond_t *c){
- pthread_cond_broadcastCounter++;
- if(isDestroyed(c))((char*)c)[2]++;
- return pthread_cond_broadcastReturns;
- }
- int pthread_cond_destroyReturns;
- int pthread_cond_destroyCounter;
- virtual int pthread_cond_destroy(pthread_cond_t *c){
- pthread_cond_destroyCounter++;
- char* p=(char*)c;
- p[0]='x';p[1]+=1;
- return pthread_cond_destroyReturns;
- }
- int pthread_cond_initReturns;
- int pthread_cond_initCounter;
- virtual int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a){
- pthread_cond_initCounter++;
- char* p=(char*)c;
- p[0]='i'; // mark as created
- p[1]=0; // destruction counter
- p[2]=0; // access after destruction counter
- return pthread_cond_initReturns;
- }
- int pthread_cond_signalReturns;
- int pthread_cond_signalCounter;
- virtual int pthread_cond_signal(pthread_cond_t *c){
- pthread_cond_signalCounter++;
- if(isDestroyed(c))((char*)c)[2]++;
- return pthread_cond_signalReturns;
- }
- int pthread_cond_timedwaitReturns;
- int pthread_cond_timedwaitCounter;
- virtual int pthread_cond_timedwait(pthread_cond_t *c,
- pthread_mutex_t *m, const struct timespec *t){
- pthread_cond_timedwaitCounter++;
- if(isDestroyed(c))((char*)c)[2]++;
- return pthread_cond_timedwaitReturns;
- }
- int pthread_cond_waitReturns;
- int pthread_cond_waitCounter;
- virtual int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m){
- pthread_cond_waitCounter++;
- if(isDestroyed(c))((char*)c)[2]++;
- return pthread_cond_waitReturns;
- }
- int pthread_mutex_destroyReturns;
- int pthread_mutex_destroyCounter;
- virtual int pthread_mutex_destroy(pthread_mutex_t *m){
- pthread_mutex_destroyCounter++;
- char* p=(char*)m;
- p[0]='x';p[1]+=1;
- return pthread_mutex_destroyReturns;
- }
- int pthread_mutex_initReturns;
- int pthread_mutex_initCounter;
- virtual int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a){
- pthread_mutex_initCounter++;
- char* p=(char*)m;
- p[0]='i'; // mark as created
- p[1]=0; // destruction counter
- p[2]=0; // access after destruction counter
- return pthread_mutex_initReturns;
- }
- int pthread_mutex_lockReturns;
- int pthread_mutex_lockCounter;
- virtual int pthread_mutex_lock(pthread_mutex_t *m){
- pthread_mutex_lockCounter++;
- if(isDestroyed(m))((char*)m)[2]++;
- return pthread_mutex_lockReturns;
- }
- int pthread_mutex_trylockReturns;
- int pthread_mutex_trylockCounter;
- virtual int pthread_mutex_trylock(pthread_mutex_t *m){
- pthread_mutex_trylockCounter++;
- if(isDestroyed(m))((char*)m)[2]++;
- return pthread_mutex_trylockReturns;
- }
- int pthread_mutex_unlockReturns;
- int pthread_mutex_unlockCounter;
- virtual int pthread_mutex_unlock(pthread_mutex_t *m){
- pthread_mutex_unlockCounter++;
- if(isDestroyed(m))((char*)m)[2]++;
- return pthread_mutex_unlockReturns;
- }
- };
- // simulates the way zookeeper threads make use of api_prolog/epilog and
- //
- class MockPthreadZKNull: public MockPthreadsNull
- {
- typedef std::map<pthread_t,zhandle_t*> Map;
- Map map_;
- public:
- virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,
- void *(*f)(void *), void *d){
- int ret=MockPthreadsNull::pthread_create(t,a,f,d);
- zhandle_t* zh=(zhandle_t*)d;
- adaptor_threads* ad=(adaptor_threads*)zh->adaptor_priv;
- api_prolog(zh);
- ad->threadsToWait--;
- putValue(map_,*t,zh);
- return ret;
- }
- virtual int pthread_join(pthread_t t, void ** r){
- zhandle_t* zh=0;
- if(getValue(map_,t,zh))
- api_epilog(zh,0);
- return MockPthreadsNull::pthread_join(t,r);
- }
- };
- struct ThreadInfo{
- typedef enum {RUNNING,TERMINATED} ThreadState;
-
- ThreadInfo():
- destructionCounter_(0),invalidAccessCounter_(0),state_(RUNNING)
- {
- }
-
- ThreadInfo& incDestroyed() {
- destructionCounter_++;
- return *this;
- }
- ThreadInfo& incInvalidAccess(){
- invalidAccessCounter_++;
- return *this;
- }
- ThreadInfo& setTerminated(){
- state_=TERMINATED;
- return *this;
- }
- int destructionCounter_;
- int invalidAccessCounter_;
- ThreadState state_;
- };
- class CheckedPthread: public MockPthreadsBase
- {
- // first => destruction counter
- // second => invalid access counter
- //typedef std::pair<int,int> Entry;
- typedef ThreadInfo Entry;
- typedef std::map<pthread_t,Entry> ThreadMap;
- static ThreadMap tmap_;
- static ThreadMap& getMap(const TypeOp<pthread_t>::BareT&){return tmap_;}
- typedef std::map<pthread_mutex_t*,Entry> MutexMap;
- static MutexMap mmap_;
- static MutexMap& getMap(const TypeOp<pthread_mutex_t>::BareT&){return mmap_;}
- typedef std::map<pthread_cond_t*,Entry> CVMap;
- static CVMap cvmap_;
- static CVMap& getMap(const TypeOp<pthread_cond_t>::BareT&){return cvmap_;}
-
- static Mutex mx;
-
- template<class T>
- static void markDestroyed(T& t){
- typedef typename TypeOp<T>::BareT Type;
- Entry e;
- synchronized(mx);
- if(getValue(getMap(Type()),t,e)){
- putValue(getMap(Type()),t,Entry(e).incDestroyed());
- }else{
- putValue(getMap(Type()),t,Entry().incDestroyed());
- }
- }
- template<class T>
- static void markCreated(T& t){
- typedef typename TypeOp<T>::BareT Type;
- Entry e;
- synchronized(mx);
- if(!getValue(getMap(Type()),t,e))
- putValue(getMap(Type()),t,Entry());
- }
- template<class T>
- static void checkAccessed(T& t){
- typedef typename TypeOp<T>::BareT Type;
- Entry e;
- synchronized(mx);
- if(getValue(getMap(Type()),t,e) && e.destructionCounter_>0)
- putValue(getMap(Type()),t,Entry(e).incInvalidAccess());
- }
- static void setTerminated(pthread_t t){
- Entry e;
- synchronized(mx);
- if(getValue(tmap_,t,e))
- putValue(tmap_,t,Entry(e).setTerminated());
- }
- public:
- bool verbose;
- CheckedPthread():verbose(false){
- tmap_.clear();
- mmap_.clear();
- cvmap_.clear();
- mx.release();
- }
- template <class T>
- static bool isInitialized(const T& t){
- typedef typename TypeOp<T>::BareT Type;
- Entry e;
- synchronized(mx);
- return getValue(getMap(Type()),t,e) && e.destructionCounter_==0;
- }
- template <class T>
- static bool isDestroyed(const T& t){
- typedef typename TypeOp<T>::BareT Type;
- Entry e;
- synchronized(mx);
- return getValue(getMap(Type()),t,e) && e.destructionCounter_>0;
- }
- static bool isTerminated(pthread_t t){
- Entry e;
- synchronized(mx);
- return getValue(tmap_,t,e) && e.state_==ThreadInfo::TERMINATED;
- }
- template <class T>
- static int getDestroyCounter(const T& t){
- typedef typename TypeOp<T>::BareT Type;
- Entry e;
- synchronized(mx);
- return getValue(getMap(Type()),t,e)?e.destructionCounter_:-1;
- }
- template<class T>
- static int getInvalidAccessCounter(const T& t){
- typedef typename TypeOp<T>::BareT Type;
- Entry e;
- synchronized(mx);
- return getValue(getMap(Type()),t,e)?e.invalidAccessCounter_:-1;
- }
- struct ThreadContext{
- typedef void *(*ThreadFunc)(void *);
-
- ThreadContext(ThreadFunc func,void* param):func_(func),param_(param){}
- ThreadFunc func_;
- void* param_;
- };
- static void* threadFuncWrapper(void* v){
- ThreadContext* ctx=(ThreadContext*)v;
- pthread_t t=pthread_self();
- markCreated(t);
- void* res=ctx->func_(ctx->param_);
- setTerminated(pthread_self());
- delete ctx;
- return res;
- }
- virtual int pthread_create(pthread_t * t, const pthread_attr_t *a,
- void *(*f)(void *), void *d)
- {
- int ret=LIBC_SYMBOLS.pthread_create(t,a,threadFuncWrapper,
- new ThreadContext(f,d));
- if(verbose)
- TEST_TRACE("thread created %p",*t);
- return ret;
- }
- virtual int pthread_join(pthread_t t, void ** r){
- if(verbose) TEST_TRACE("thread joined %p",t);
- int ret=LIBC_SYMBOLS.pthread_join(t,r);
- if(ret==0)
- markDestroyed(t);
- return ret;
- }
- virtual int pthread_detach(pthread_t t){
- if(verbose) TEST_TRACE("thread detached %p",t);
- int ret=LIBC_SYMBOLS.pthread_detach(t);
- if(ret==0)
- markDestroyed(t);
- return ret;
- }
- virtual int pthread_cond_broadcast(pthread_cond_t *c){
- checkAccessed(c);
- return LIBC_SYMBOLS.pthread_cond_broadcast(c);
- }
- virtual int pthread_cond_destroy(pthread_cond_t *c){
- markDestroyed(c);
- return LIBC_SYMBOLS.pthread_cond_destroy(c);
- }
- virtual int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a){
- markCreated(c);
- return LIBC_SYMBOLS.pthread_cond_init(c,a);
- }
- virtual int pthread_cond_signal(pthread_cond_t *c){
- checkAccessed(c);
- return LIBC_SYMBOLS.pthread_cond_signal(c);
- }
- virtual int pthread_cond_timedwait(pthread_cond_t *c,
- pthread_mutex_t *m, const struct timespec *t){
- checkAccessed(c);
- return LIBC_SYMBOLS.pthread_cond_timedwait(c,m,t);
- }
- virtual int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m){
- checkAccessed(c);
- return LIBC_SYMBOLS.pthread_cond_wait(c,m);
- }
- virtual int pthread_mutex_destroy(pthread_mutex_t *m){
- markDestroyed(m);
- return LIBC_SYMBOLS.pthread_mutex_destroy(m);
- }
- virtual int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a){
- markCreated(m);
- return LIBC_SYMBOLS.pthread_mutex_init(m,a);
- }
- virtual int pthread_mutex_lock(pthread_mutex_t *m){
- checkAccessed(m);
- return LIBC_SYMBOLS.pthread_mutex_lock(m);
- }
- virtual int pthread_mutex_trylock(pthread_mutex_t *m){
- checkAccessed(m);
- return LIBC_SYMBOLS.pthread_mutex_trylock(m);
- }
- virtual int pthread_mutex_unlock(pthread_mutex_t *m){
- checkAccessed(m);
- return LIBC_SYMBOLS.pthread_mutex_unlock(m);
- }
- };
- #endif /*PTHREADMOCKS_H_*/
|