tcs.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  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 "tcs.h"
  32. #include "se_trace.h"
  33. #include "sgx_error.h"
  34. #include "se_memory.h"
  35. #include "se_thread.h"
  36. #include <assert.h>
  37. extern se_thread_id_t get_thread_id();
  38. CTrustThread::CTrustThread(tcs_t *tcs, CEnclave* enclave)
  39. : m_tcs(tcs)
  40. , m_enclave(enclave)
  41. , m_reference(0)
  42. , m_event(NULL)
  43. {
  44. memset(&m_tcs_info, 0, sizeof(debug_tcs_info_t));
  45. m_tcs_info.TCS_address = reinterpret_cast<void*>(tcs);
  46. m_tcs_info.ocall_frame = 0;
  47. m_tcs_info.thread_id = 0;
  48. }
  49. CTrustThread::~CTrustThread()
  50. {
  51. se_event_destroy(m_event);
  52. m_event = NULL;
  53. }
  54. se_handle_t CTrustThread::get_event()
  55. {
  56. if (m_event == NULL)
  57. m_event = se_event_init();
  58. return m_event;
  59. }
  60. void CTrustThread::push_ocall_frame(ocall_frame_t* frame_point)
  61. {
  62. frame_point->index = this->get_reference();
  63. frame_point->pre_last_frame = m_tcs_info.ocall_frame;
  64. m_tcs_info.ocall_frame = reinterpret_cast<uintptr_t>(frame_point);
  65. m_tcs_info.thread_id = get_thread_id();
  66. }
  67. void CTrustThread::pop_ocall_frame()
  68. {
  69. ocall_frame_t* last_ocall_frame = reinterpret_cast<ocall_frame_t*>(m_tcs_info.ocall_frame);
  70. if (last_ocall_frame)
  71. {
  72. m_tcs_info.ocall_frame = last_ocall_frame->pre_last_frame;
  73. }
  74. }
  75. CTrustThreadPool::CTrustThreadPool()
  76. {
  77. m_thread_list = NULL;
  78. }
  79. CTrustThreadPool::~CTrustThreadPool()
  80. {
  81. LockGuard lock(&m_thread_mutex);
  82. //destroy free tcs list
  83. for(vector<CTrustThread *>::iterator it=m_free_thread_vector.begin(); it!=m_free_thread_vector.end(); it++)
  84. {
  85. delete *it;
  86. }
  87. m_free_thread_vector.clear();
  88. //destroy thread cache
  89. Node<se_thread_id_t, CTrustThread*>* it = m_thread_list, *tmp = NULL;
  90. while (it != NULL)
  91. {
  92. delete it->value;
  93. tmp = it;
  94. it = it->next;
  95. delete tmp;
  96. }
  97. m_thread_list = NULL;
  98. }
  99. void get_thread_set(vector<se_thread_id_t> &thread_vector);
  100. inline int CTrustThreadPool::find_thread(vector<se_thread_id_t> &thread_vector, se_thread_id_t thread_id)
  101. {
  102. for(vector<se_thread_id_t>::iterator it=thread_vector.begin(); it!=thread_vector.end(); it++)
  103. if(*it == thread_id)
  104. return TRUE;
  105. return FALSE;
  106. }
  107. inline CTrustThread * CTrustThreadPool::get_free_thread()
  108. {
  109. if(true == m_free_thread_vector.empty())
  110. {
  111. return NULL;
  112. }
  113. //if there is free tcs, remove it from free list
  114. CTrustThread *thread_node = m_free_thread_vector.back();
  115. m_free_thread_vector.pop_back();
  116. return thread_node;
  117. }
  118. //This tcs policy is bind tcs with one thread.
  119. int CTrustThreadPool::bind_thread(const se_thread_id_t thread_id, CTrustThread * const trust_thread)
  120. {
  121. if (m_thread_list == NULL) {
  122. m_thread_list = new Node<se_thread_id_t, CTrustThread*>(thread_id, trust_thread);
  123. } else {
  124. Node<se_thread_id_t, CTrustThread*>* it = new Node<se_thread_id_t, CTrustThread*>(thread_id, trust_thread);
  125. if (m_thread_list->InsertNext(it) == false) {
  126. delete it;
  127. SE_TRACE(SE_TRACE_WARNING, "trust thread %x is already added to the list\n", trust_thread);
  128. return FALSE;
  129. }
  130. }
  131. return TRUE;
  132. }
  133. CTrustThread * CTrustThreadPool::get_bound_thread(const se_thread_id_t thread_id)
  134. {
  135. CTrustThread *trust_thread = NULL;
  136. Node<se_thread_id_t, CTrustThread*>* it = m_thread_list->Find(thread_id);
  137. if(it != NULL)
  138. trust_thread = it->value;
  139. return trust_thread;
  140. }
  141. CTrustThread * CTrustThreadPool::add_thread(tcs_t * const tcs, CEnclave * const enclave)
  142. {
  143. CTrustThread *trust_thread = new CTrustThread(tcs, enclave);
  144. LockGuard lock(&m_thread_mutex);
  145. //add tcs to free list
  146. m_free_thread_vector.push_back(trust_thread);
  147. return trust_thread;
  148. }
  149. CTrustThread *CTrustThreadPool::get_bound_thread(const tcs_t *tcs)
  150. {
  151. //Since now this function will be call outside, we need get lock to protect map
  152. LockGuard lock(&m_thread_mutex);
  153. CTrustThread *trust_thread = NULL;
  154. if (m_thread_list == NULL)
  155. return NULL;
  156. Node<se_thread_id_t, CTrustThread*>* it = m_thread_list;
  157. while (it != NULL) {
  158. trust_thread = it->value;
  159. if(trust_thread->get_tcs() == tcs) {
  160. return trust_thread;
  161. }
  162. it = it->next;
  163. }
  164. return NULL;
  165. }
  166. void CTrustThreadPool::reset()
  167. {
  168. //get lock at the begin of list walk.
  169. LockGuard lock(&m_thread_mutex);
  170. //walk through thread cache to free every element;
  171. Node<se_thread_id_t, CTrustThread*>* it = m_thread_list, *tmp = NULL;
  172. while(it != NULL)
  173. {
  174. tmp = it;
  175. it = it->next;
  176. CTrustThread *trust_thread = tmp->value;
  177. //remove from thread cache
  178. delete tmp;
  179. trust_thread->reset_ref();
  180. m_free_thread_vector.push_back(trust_thread);
  181. }
  182. m_thread_list = NULL;
  183. return;
  184. }
  185. void CTrustThreadPool::wake_threads()
  186. {
  187. LockGuard lock(&m_thread_mutex);
  188. Node<se_thread_id_t, CTrustThread*>* it = m_thread_list;
  189. while (it != NULL) {
  190. CTrustThread *thread = it->value;
  191. se_handle_t event = thread->get_event();
  192. se_event_wake(event);
  193. it = it->next;
  194. }
  195. }
  196. CTrustThread * CTrustThreadPool::_acquire_thread()
  197. {
  198. //try to get tcs from thread cache
  199. se_thread_id_t thread_id = get_thread_id();
  200. CTrustThread *trust_thread = get_bound_thread(thread_id);
  201. if(NULL != trust_thread)
  202. {
  203. return trust_thread;
  204. }
  205. //try get tcs from free list;
  206. trust_thread = get_free_thread();
  207. //if there is no free tcs, collect useless tcs.
  208. if(NULL == trust_thread)
  209. {
  210. if(!garbage_collect())
  211. return NULL;
  212. //get tcs from free list again.
  213. trust_thread = get_free_thread();
  214. assert(NULL != trust_thread);
  215. }
  216. //we have got a free tcs. add the tcs to thread cache
  217. bind_thread(thread_id, trust_thread);
  218. return trust_thread;
  219. }
  220. CTrustThread * CTrustThreadPool::acquire_thread()
  221. {
  222. LockGuard lock(&m_thread_mutex);
  223. CTrustThread *trust_thread = NULL;
  224. trust_thread = _acquire_thread();
  225. if(trust_thread)
  226. trust_thread->increase_ref();
  227. return trust_thread;
  228. }
  229. //Do nothing for bind mode, the tcs is always bound to a thread.
  230. void CTrustThreadPool::release_thread(CTrustThread * const trust_thread)
  231. {
  232. LockGuard lock(&m_thread_mutex);
  233. trust_thread->decrease_ref();
  234. return;
  235. }
  236. //The return value stand for the number of free trust thread.
  237. int CThreadPoolBindMode::garbage_collect()
  238. {
  239. int nr_free = 0;
  240. //if free list is NULL, recycle tcs.
  241. //get thread id set of current process
  242. vector<se_thread_id_t> thread_vector;
  243. get_thread_set(thread_vector);
  244. //walk through thread cache to see if there is any thread that has exited
  245. Node<se_thread_id_t, CTrustThread*>* it = m_thread_list, *pre = NULL, *tmp = NULL;
  246. while(it != NULL)
  247. {
  248. se_thread_id_t thread_id = it->key;
  249. //if the thread has exited
  250. if(FALSE == find_thread(thread_vector, thread_id))
  251. {
  252. //if the reference is not 0, there must be some wrong termination, so we can't recycle such trust thread.
  253. //return to free_tcs list
  254. if(0 == it->value->get_reference())
  255. {
  256. m_free_thread_vector.push_back(it->value);
  257. nr_free++;
  258. }
  259. else
  260. {
  261. //the list only record the pointer of trust thread, so we can delete it first and then erase from map.
  262. delete it->value;
  263. }
  264. tmp = it;
  265. it = it->next;
  266. if (tmp == m_thread_list)
  267. m_thread_list = it;
  268. if (pre != NULL)
  269. pre->next = it;
  270. //remove from thread cache
  271. delete tmp;
  272. }
  273. else
  274. {
  275. pre = it;
  276. it = it->next;
  277. }
  278. }
  279. return nr_free;
  280. }
  281. int CThreadPoolUnBindMode::garbage_collect()
  282. {
  283. int nr_free = 0;
  284. //walk through to free unused trust thread
  285. Node<se_thread_id_t, CTrustThread*>* it = m_thread_list, *pre = NULL, *tmp = NULL;
  286. while(it != NULL)
  287. {
  288. //if the reference is 0, then the trust thread is not in use, so return to free_tcs list
  289. if(0 == it->value->get_reference())
  290. {
  291. m_free_thread_vector.push_back(it->value);
  292. nr_free++;
  293. tmp = it;
  294. it = it->next;
  295. if (tmp == m_thread_list)
  296. m_thread_list = it;
  297. if (pre != NULL)
  298. pre->next = it;
  299. //remove from thread cache
  300. delete tmp;
  301. }
  302. else
  303. {
  304. pre = it;
  305. it = it->next;
  306. }
  307. }
  308. return nr_free;
  309. }