aesm_long_lived_thread.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. /*
  2. * Copyright (C) 2011-2016 Intel Corporation. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in
  12. * the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Intel Corporation nor the names of its
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. */
  31. #include "aesm_long_lived_thread.h"
  32. #include "pve_logic.h"
  33. #include "platform_info_logic.h"
  34. #include "oal/internal_log.h"
  35. #include "se_time.h"
  36. #include "se_wrapper.h"
  37. #include <time.h>
  38. #include <assert.h>
  39. #include <list>
  40. #include "LEClass.h"
  41. enum _thread_state
  42. {
  43. ths_idle,
  44. ths_busy,
  45. ths_stop//The thread is to be stopped and no new job will be accepted
  46. };
  47. enum _io_cache_state
  48. {
  49. ioc_idle, //thread has been finished
  50. ioc_busy, //thread not finished yet
  51. ioc_stop //thread stop required
  52. };
  53. #define MAX_OUTPUT_CACHE 50
  54. #define THREAD_INFINITE_TICK_COUNT 0xFFFFFFFFFFFFFFFFLL
  55. class ThreadStatus;
  56. class BaseThreadIOCache;
  57. typedef ae_error_t (*long_lived_thread_func_t)(BaseThreadIOCache *cache);
  58. //Base class for cached data of each thread to fork
  59. class BaseThreadIOCache:private Uncopyable{
  60. time_t timeout; //The data will timeout after the time if the state is not busy
  61. int ref_count; //ref_count is used to track how many threads are currently referencing the data
  62. _io_cache_state status;
  63. //handle of the thread, some thread will be waited by other threads so that we could not
  64. // free the handle until all other threads have got notification that the thread is terminated
  65. aesm_thread_t thread_handle;
  66. friend class ThreadStatus;
  67. protected:
  68. ae_error_t ae_ret;
  69. BaseThreadIOCache():ref_count(0),status(ioc_busy){
  70. timeout=0;
  71. thread_handle=NULL;
  72. ae_ret = AE_FAILURE;
  73. }
  74. virtual ThreadStatus& get_thread()=0;
  75. public:
  76. virtual ae_error_t entry(void)=0;
  77. virtual bool operator==(const BaseThreadIOCache& oc)const=0;
  78. ae_error_t start(BaseThreadIOCache *&out_ioc, uint32_t timeout=THREAD_TIMEOUT);
  79. void deref(void);
  80. void set_status_finish();
  81. public:
  82. virtual ~BaseThreadIOCache(){}
  83. };
  84. class ThreadStatus: private Uncopyable
  85. {
  86. private:
  87. AESMLogicMutex thread_mutex;
  88. _thread_state thread_state;
  89. uint64_t status_clock;
  90. BaseThreadIOCache *cur_iocache;
  91. std::list<BaseThreadIOCache *>output_cache;
  92. protected:
  93. friend class BaseThreadIOCache;
  94. //function to look up cached output, there will be no real thread associated with the input ioc
  95. //If a match is found the input parameter will be free automatically and the matched value is returned
  96. //return true if a thread will be forked for the out_ioc
  97. bool find_or_insert_iocache(BaseThreadIOCache* ioc, BaseThreadIOCache *&out_ioc)
  98. {
  99. AESMLogicLock locker(thread_mutex);
  100. std::list<BaseThreadIOCache *>::reverse_iterator it;
  101. out_ioc=NULL;
  102. if(thread_state == ths_stop){
  103. AESM_DBG_TRACE("thread %p has been stopped and ioc %p not inserted", this,ioc);
  104. delete ioc;
  105. return false;//never visit any item after thread is stopped
  106. }
  107. time_t cur=time(NULL);
  108. AESM_DBG_TRACE("cache size %d",(int)output_cache.size());
  109. BaseThreadIOCache *remove_candidate = NULL;
  110. for(it=output_cache.rbegin();it!=output_cache.rend();++it){//visit the cache in reverse order so that the newest item will be visited firstly
  111. BaseThreadIOCache *pioc=*it;
  112. if((pioc->status==ioc_idle)&&(pioc->timeout<cur)){
  113. if(pioc->ref_count==0&&remove_candidate==NULL){
  114. remove_candidate = pioc;
  115. }
  116. continue;//value timeout
  117. }
  118. if(*pioc==*ioc){//matched value find
  119. pioc->ref_count++;//reference it
  120. AESM_DBG_TRACE("IOC %p matching input IOC %p (ref_count:%d,status:%d,timeout:%d) in thread %p",pioc, ioc,(int)pioc->ref_count,(int)pioc->status, (int)pioc->timeout, this);
  121. out_ioc= pioc;
  122. delete ioc;
  123. return false;
  124. }
  125. }
  126. if(thread_state == ths_busy){//It is not permitted to insert in busy status
  127. AESM_DBG_TRACE("thread busy when trying insert input ioc %p",ioc);
  128. delete ioc;
  129. return false;
  130. }
  131. if(remove_candidate!=NULL){
  132. output_cache.remove(remove_candidate);
  133. delete remove_candidate;
  134. }
  135. if(output_cache.size()>=MAX_OUTPUT_CACHE){
  136. std::list<BaseThreadIOCache *>::iterator fit;
  137. bool erased=false;
  138. for(fit = output_cache.begin(); fit!=output_cache.end();++fit){
  139. BaseThreadIOCache *pioc=*fit;
  140. if(pioc->ref_count==0){//find a not timeout item to remove
  141. assert(pioc->status==ioc_idle);
  142. AESM_DBG_TRACE("erase idle ioc %p", pioc);
  143. output_cache.erase(fit);
  144. erased = true;
  145. AESM_DBG_TRACE("thread %p cache size %d",this, output_cache.size());
  146. delete pioc;
  147. break;
  148. }
  149. }
  150. if(!erased){//no item could be removed
  151. AESM_DBG_TRACE("no free ioc found and cannot insert ioc %p",ioc);
  152. delete ioc;
  153. return false;//similar as busy status
  154. }
  155. }
  156. output_cache.push_back(ioc);
  157. out_ioc = cur_iocache = ioc;
  158. cur_iocache->ref_count=2;//initialize to be refenced by parent thread and the thread itself
  159. thread_state = ths_busy;//mark thread to be busy that the thread to be started
  160. AESM_DBG_TRACE("successfully add ioc %p (status=%d,timeout=%d) into thread %p",out_ioc, (int)out_ioc->status, (int)out_ioc->timeout, this);
  161. return true;
  162. }
  163. public:
  164. ThreadStatus():output_cache()
  165. {
  166. thread_state = ths_idle;
  167. status_clock = 0;
  168. cur_iocache = NULL;
  169. }
  170. void set_status_finish(BaseThreadIOCache* ioc);//only called at the end of aesm_long_lived_thread_entry
  171. void deref(BaseThreadIOCache* iocache);
  172. ae_error_t wait_iocache_timeout(BaseThreadIOCache* ioc, uint64_t stop_tick_count);
  173. //create thread and wait at most 'timeout' for the thread to be finished
  174. // It will first look up whether there is a previous run with same input before starting the thread
  175. // we should not delete ioc after calling to this function
  176. ae_error_t set_thread_start(BaseThreadIOCache* ioc, BaseThreadIOCache *&out_ioc, uint32_t timeout=THREAD_TIMEOUT);
  177. void stop_thread(uint64_t stop_milli_second);//We need wait for thread to be terminated and all thread_handle in list to be closed
  178. ~ThreadStatus(){stop_thread(THREAD_INFINITE_TICK_COUNT);}//ThreadStatus instance should be global object. Otherwise, it is possible that the object is destroyed before a thread waiting for and IOCache got notified and causing exception
  179. ae_error_t wait_for_cur_thread(uint64_t millisecond);
  180. //function to query whether current thread is idle,
  181. //if it is idle, return true and reset clock to current clock value
  182. bool query_status_and_reset_clock(void);
  183. };
  184. ae_error_t BaseThreadIOCache::start(BaseThreadIOCache *&out_ioc, uint32_t timeout_value)
  185. {
  186. return get_thread().set_thread_start(this, out_ioc, timeout_value);
  187. }
  188. void BaseThreadIOCache::deref(void)
  189. {
  190. get_thread().deref(this);
  191. }
  192. void BaseThreadIOCache::set_status_finish(void)
  193. {
  194. get_thread().set_status_finish(this);
  195. }
  196. //This is thread entry wrapper for all threads
  197. static ae_error_t aesm_long_lived_thread_entry(aesm_thread_arg_type_t arg)
  198. {
  199. BaseThreadIOCache *cache=(BaseThreadIOCache *)arg;
  200. ae_error_t ae_err = cache->entry();
  201. cache->set_status_finish();
  202. return ae_err;
  203. }
  204. void ThreadStatus::stop_thread(uint64_t stop_tick_count)
  205. {
  206. //change state to stop
  207. thread_mutex.lock();
  208. thread_state = ths_stop;
  209. do{
  210. std::list<BaseThreadIOCache *>::iterator it;
  211. for(it=output_cache.begin(); it!=output_cache.end();++it){
  212. BaseThreadIOCache *p=*it;
  213. if(p->status != ioc_stop){//It has not been processed
  214. p->status = ioc_stop;
  215. break;
  216. }
  217. }
  218. if(it!=output_cache.end()){//found item to stop
  219. BaseThreadIOCache *p=*it;
  220. p->ref_count++;
  221. thread_mutex.unlock();
  222. wait_iocache_timeout(p, stop_tick_count);
  223. thread_mutex.lock();
  224. }else{
  225. break;
  226. }
  227. }while(1);
  228. thread_mutex.unlock();
  229. //This function should only be called at AESM exit
  230. //Leave memory leak here is OK and all pointer to BaseThreadIOCache will not be released
  231. }
  232. ae_error_t ThreadStatus::wait_for_cur_thread(uint64_t millisecond)
  233. {
  234. BaseThreadIOCache *ioc=NULL;
  235. uint64_t stop_tick_count;
  236. if(millisecond == AESM_THREAD_INFINITE){
  237. stop_tick_count = THREAD_INFINITE_TICK_COUNT;
  238. }else{
  239. stop_tick_count = se_get_tick_count() + (millisecond*se_get_tick_count_freq()+500)/1000;
  240. }
  241. thread_mutex.lock();
  242. if(cur_iocache!=NULL){
  243. ioc = cur_iocache;
  244. ioc->ref_count++;
  245. }
  246. thread_mutex.unlock();
  247. if(ioc!=NULL){
  248. return wait_iocache_timeout(ioc, stop_tick_count);
  249. }
  250. return AE_SUCCESS;
  251. }
  252. ae_error_t ThreadStatus::wait_iocache_timeout(BaseThreadIOCache* ioc, uint64_t stop_tick_count)
  253. {
  254. ae_error_t ae_ret=AE_SUCCESS;
  255. uint64_t cur_tick_count = se_get_tick_count();
  256. uint64_t freq = se_get_tick_count_freq();
  257. bool need_wait=false;
  258. aesm_thread_t handle=NULL;
  259. thread_mutex.lock();
  260. if(ioc->thread_handle!=NULL&&(cur_tick_count<stop_tick_count||stop_tick_count==THREAD_INFINITE_TICK_COUNT)){
  261. AESM_DBG_TRACE("wait for busy ioc %p(refcount=%d)",ioc,ioc->ref_count);
  262. need_wait = true;
  263. handle = ioc->thread_handle;
  264. }
  265. thread_mutex.unlock();
  266. if(need_wait){
  267. unsigned long diff_time;
  268. if(stop_tick_count == THREAD_INFINITE_TICK_COUNT){
  269. diff_time = AESM_THREAD_INFINITE;
  270. }else{
  271. double wtime=(double)(stop_tick_count-cur_tick_count)*1000.0/(double)freq;
  272. diff_time = (unsigned long)(wtime+0.5);
  273. }
  274. ae_ret= aesm_wait_thread(handle, &ae_ret, diff_time);
  275. }
  276. deref(ioc);
  277. return ae_ret;
  278. }
  279. void ThreadStatus::deref(BaseThreadIOCache *ioc)
  280. {
  281. aesm_thread_t handle = NULL;
  282. time_t cur=time(NULL);
  283. {
  284. AESMLogicLock locker(thread_mutex);
  285. AESM_DBG_TRACE("deref ioc %p (ref_count=%d,status=%d,timeout=%d) of thread %p",ioc,(int)ioc->ref_count,(int)ioc->status,(int)ioc->timeout, this);
  286. --ioc->ref_count;
  287. if(ioc->ref_count == 0){//try free the thread handle now
  288. handle = ioc->thread_handle;
  289. ioc->thread_handle = NULL;
  290. if(ioc->status == ioc_busy){
  291. ioc->status = ioc_idle;
  292. }
  293. AESM_DBG_TRACE("free thread handle for ioc %p",ioc);
  294. }
  295. if(ioc->ref_count==0 &&(ioc->status==ioc_stop||ioc->timeout<cur)){
  296. AESM_DBG_TRACE("free ioc %p",ioc);
  297. output_cache.remove(ioc);
  298. AESM_DBG_TRACE("thread %p cache's size is %d",this, (int)output_cache.size());
  299. delete ioc;
  300. }
  301. }
  302. if(handle!=NULL){
  303. aesm_free_thread(handle);
  304. }
  305. }
  306. ae_error_t ThreadStatus::set_thread_start(BaseThreadIOCache* ioc, BaseThreadIOCache *&out_ioc, uint32_t timeout)
  307. {
  308. ae_error_t ae_ret = AE_SUCCESS;
  309. ae_error_t ret = AE_FAILURE;
  310. out_ioc=NULL;
  311. bool fork_required = find_or_insert_iocache(ioc, out_ioc);
  312. if(fork_required){
  313. ae_ret = aesm_create_thread(aesm_long_lived_thread_entry, (aesm_thread_arg_type_t)out_ioc, &out_ioc->thread_handle);
  314. if (ae_ret != AE_SUCCESS)
  315. {
  316. AESM_DBG_TRACE("fail to create thread for ioc %p",out_ioc);
  317. AESMLogicLock locker(thread_mutex);
  318. thread_state = ths_idle;
  319. out_ioc->status = ioc_idle;//set to finished status
  320. cur_iocache = NULL;
  321. deref(out_ioc);
  322. return ae_ret;
  323. }else{
  324. AESM_DBG_TRACE("succ create thread %p for ioc %p",this, out_ioc);
  325. }
  326. }
  327. if(out_ioc == NULL){
  328. AESM_DBG_TRACE("no ioc created for input ioc %p in thread %p",ioc, this);
  329. return OAL_THREAD_TIMEOUT_ERROR;
  330. }
  331. {//check whether thread has been finished
  332. AESMLogicLock locker(thread_mutex);
  333. if(out_ioc->status!=ioc_busy){//job is done
  334. AESM_DBG_TRACE("job done for ioc %p (status=%d,timeout=%d,ref_count=%d) in thread %p",out_ioc, (int)out_ioc->status,(int)out_ioc->timeout,(int)out_ioc->ref_count,this);
  335. return AE_SUCCESS;
  336. }
  337. }
  338. if(timeout >= AESM_THREAD_INFINITE ){
  339. ae_ret = aesm_join_thread(out_ioc->thread_handle, &ret);
  340. }else{
  341. uint64_t now = se_get_tick_count();
  342. double timediff = static_cast<double>(timeout) - (static_cast<double>(now - status_clock))/static_cast<double>(se_get_tick_count_freq()) *1000;
  343. if (timediff <= 0.0) {
  344. AESM_DBG_ERROR("long flow thread timeout");
  345. return OAL_THREAD_TIMEOUT_ERROR;
  346. }
  347. else{
  348. AESM_DBG_TRACE("timeout:%u,timediff: %f", timeout,timediff);
  349. ae_ret = aesm_wait_thread(out_ioc->thread_handle, &ret, (unsigned long)timediff);
  350. }
  351. }
  352. AESM_DBG_TRACE("wait for ioc %p (status=%d,timeout=%d,ref_count=%d) result:%d",out_ioc,(int)out_ioc->status,(int)out_ioc->timeout,(int)out_ioc->ref_count, ae_ret);
  353. return ae_ret;
  354. };
  355. #define TIMEOUT_SHORT_TIME 60
  356. #define TIMEOUT_FOR_A_WHILE (5*60)
  357. #define TIMEOUT_LONG_TIME (3600*24) //at most once every day
  358. static time_t get_timeout_via_ae_error(ae_error_t ae)
  359. {
  360. time_t cur=time(NULL);
  361. switch(ae){
  362. case AE_SUCCESS:
  363. case OAL_PROXY_SETTING_ASSIST:
  364. case OAL_NETWORK_RESEND_REQUIRED:
  365. return cur-1;//always timeout, the error code will never be reused
  366. case PVE_INTEGRITY_CHECK_ERROR:
  367. case OAL_NETWORK_UNAVAILABLE_ERROR:
  368. case OAL_NETWORK_BUSY:
  369. case PVE_SERVER_BUSY_ERROR:
  370. return cur+TIMEOUT_SHORT_TIME; //retry after short time
  371. case QE_REVOKED_ERROR:
  372. case PVE_REVOKED_ERROR:
  373. case PVE_MSG_ERROR:
  374. case PVE_PERFORMANCE_REKEY_NOT_SUPPORTED:
  375. case PSW_UPDATE_REQUIRED:
  376. return cur+TIMEOUT_LONG_TIME;
  377. default:
  378. return cur+TIMEOUT_SHORT_TIME;//retry quicky for unknown error
  379. }
  380. }
  381. void ThreadStatus::set_status_finish(BaseThreadIOCache* ioc)
  382. {
  383. aesm_thread_t handle = NULL;
  384. {
  385. AESMLogicLock locker(thread_mutex);
  386. assert(thread_state==ths_busy||thread_state==ths_stop);
  387. assert(ioc->status == ioc_busy);
  388. AESM_DBG_TRACE("set finish status for ioc %p(status=%d,timeout=%d,ref_count=%d) of thread %p",ioc, (int)ioc->status,(int)ioc->timeout,(int)ioc->ref_count,this);
  389. if(thread_state==ths_busy){
  390. AESM_DBG_TRACE("set thread %p to idle", this);
  391. thread_state=ths_idle;
  392. cur_iocache = NULL;
  393. }
  394. ioc->status=ioc_idle;
  395. ioc->ref_count--;
  396. ioc->timeout = get_timeout_via_ae_error(ioc->ae_ret);
  397. if(ioc->ref_count==0){//try free thread handle
  398. handle = ioc->thread_handle;
  399. ioc->thread_handle = NULL;
  400. AESM_DBG_TRACE("thread handle release for ioc %p and status to idle of thread %p",ioc, this);
  401. }
  402. }
  403. if(handle!=NULL){
  404. aesm_free_thread(handle);
  405. }
  406. }
  407. bool ThreadStatus::query_status_and_reset_clock(void)
  408. {
  409. AESMLogicLock locker(thread_mutex);
  410. if(thread_state == ths_busy || thread_state == ths_stop)
  411. return false;
  412. status_clock = se_get_tick_count();
  413. return true;
  414. }
  415. //Code above implement logic of threads in the AESM Service
  416. //Code below to define IOCache of each thread
  417. static ThreadStatus epid_thread;
  418. static ThreadStatus white_list_thread;
  419. class EpidProvIOCache:public BaseThreadIOCache{
  420. bool performance_rekey;//input
  421. protected:
  422. EpidProvIOCache(bool perf_rekey){
  423. this->performance_rekey = perf_rekey;
  424. }
  425. virtual ae_error_t entry(void);
  426. virtual ThreadStatus& get_thread();
  427. friend ae_error_t start_epid_provision_thread(bool performance_rekey, unsigned long timeout);
  428. public:
  429. virtual bool operator==(const BaseThreadIOCache& oc)const{
  430. const EpidProvIOCache *p=dynamic_cast<const EpidProvIOCache *>(&oc);
  431. if(p==NULL)return false;
  432. return performance_rekey==p->performance_rekey;//only compare input
  433. }
  434. };
  435. class WhiteListIOCache :public BaseThreadIOCache{
  436. //no input to be cached for white list pulling
  437. protected:
  438. WhiteListIOCache(void){
  439. }
  440. virtual ae_error_t entry(void);
  441. virtual ThreadStatus& get_thread();
  442. friend ae_error_t start_white_list_thread(unsigned long timeout);
  443. public:
  444. virtual bool operator==(const BaseThreadIOCache& oc)const{
  445. const WhiteListIOCache *p = dynamic_cast<const WhiteListIOCache*>(&oc);
  446. if (p == NULL) return false;
  447. return true;
  448. }
  449. };
  450. ThreadStatus& EpidProvIOCache::get_thread()
  451. {
  452. return epid_thread;
  453. }
  454. ThreadStatus& WhiteListIOCache::get_thread()
  455. {
  456. return white_list_thread;
  457. }
  458. ae_error_t EpidProvIOCache::entry()
  459. {
  460. return ae_ret = PvEAESMLogic::epid_provision_thread_func(performance_rekey);
  461. }
  462. ae_error_t WhiteListIOCache::entry()
  463. {
  464. return ae_ret = CLEClass::update_white_list_by_url();
  465. }
  466. //start implementation of external functions
  467. #define INIT_THREAD(cache_type, timeout, init_list) \
  468. BaseThreadIOCache *ioc = new cache_type init_list; \
  469. BaseThreadIOCache *out_ioc = NULL; \
  470. ae_error_t ae_ret = AE_FAILURE; \
  471. ae_ret = ioc->start(out_ioc, (uint32_t)(timeout)); \
  472. if(ae_ret != AE_SUCCESS){ \
  473. if(out_ioc!=NULL){out_ioc->deref();}\
  474. return ae_ret; \
  475. }\
  476. assert(out_ioc!=NULL);\
  477. cache_type *pioc = dynamic_cast<cache_type *>(out_ioc);\
  478. assert(pioc!=NULL);
  479. //now the thread has finished it's execution and we could read result without lock
  480. #define COPY_OUTPUT(x) x=pioc->x
  481. #define FINI_THREAD() \
  482. ae_ret = pioc->ae_ret;\
  483. pioc->deref();/*derefence the cache object after usage of it*/ \
  484. return ae_ret;
  485. //usage model
  486. //INIT_THREAD(thread_used, cache_type, timeout, init_list)
  487. // COPY_OUTPUT(is_new_pairing);// copy out output parameter except for return value from pioc object to output parameter, such as
  488. //FINI_THREAD(thread_used)
  489. ae_error_t start_epid_provision_thread(bool performance_rekey, unsigned long timeout)
  490. {
  491. INIT_THREAD(EpidProvIOCache, timeout, (performance_rekey))
  492. FINI_THREAD()
  493. }
  494. ae_error_t start_white_list_thread(unsigned long timeout)
  495. {
  496. INIT_THREAD(WhiteListIOCache, timeout, ())
  497. FINI_THREAD()
  498. }
  499. bool query_pve_thread_status(void)
  500. {
  501. return epid_thread.query_status_and_reset_clock();
  502. }
  503. ae_error_t wait_pve_thread(uint64_t time_out_milliseconds)
  504. {
  505. return epid_thread.wait_for_cur_thread(time_out_milliseconds);
  506. }
  507. void stop_all_long_lived_threads(uint64_t time_out_milliseconds)
  508. {
  509. uint64_t freq = se_get_tick_count_freq();
  510. uint64_t stop_tick_count = se_get_tick_count()+(time_out_milliseconds*freq+500)/1000;
  511. epid_thread.stop_thread(stop_tick_count);
  512. white_list_thread.stop_thread(stop_tick_count);
  513. }