tcs.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /*
  2. * Copyright (C) 2011-2017 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 = nullptr;
  136. if (m_thread_list)
  137. {
  138. auto it = m_thread_list->Find(thread_id);
  139. if (it)
  140. trust_thread = it->value;
  141. }
  142. return trust_thread;
  143. }
  144. CTrustThread * CTrustThreadPool::add_thread(tcs_t * const tcs, CEnclave * const enclave)
  145. {
  146. CTrustThread *trust_thread = new CTrustThread(tcs, enclave);
  147. LockGuard lock(&m_thread_mutex);
  148. //add tcs to free list
  149. m_free_thread_vector.push_back(trust_thread);
  150. return trust_thread;
  151. }
  152. CTrustThread *CTrustThreadPool::get_bound_thread(const tcs_t *tcs)
  153. {
  154. //Since now this function will be call outside, we need get lock to protect map
  155. LockGuard lock(&m_thread_mutex);
  156. CTrustThread *trust_thread = NULL;
  157. if (m_thread_list == NULL)
  158. return NULL;
  159. Node<se_thread_id_t, CTrustThread*>* it = m_thread_list;
  160. while (it != NULL) {
  161. trust_thread = it->value;
  162. if(trust_thread->get_tcs() == tcs) {
  163. return trust_thread;
  164. }
  165. it = it->next;
  166. }
  167. return NULL;
  168. }
  169. void CTrustThreadPool::reset()
  170. {
  171. //get lock at the begin of list walk.
  172. LockGuard lock(&m_thread_mutex);
  173. //walk through thread cache to free every element;
  174. Node<se_thread_id_t, CTrustThread*>* it = m_thread_list, *tmp = NULL;
  175. while(it != NULL)
  176. {
  177. tmp = it;
  178. it = it->next;
  179. CTrustThread *trust_thread = tmp->value;
  180. //remove from thread cache
  181. delete tmp;
  182. trust_thread->reset_ref();
  183. m_free_thread_vector.push_back(trust_thread);
  184. }
  185. m_thread_list = NULL;
  186. return;
  187. }
  188. void CTrustThreadPool::wake_threads()
  189. {
  190. LockGuard lock(&m_thread_mutex);
  191. Node<se_thread_id_t, CTrustThread*>* it = m_thread_list;
  192. while (it != NULL) {
  193. CTrustThread *thread = it->value;
  194. se_handle_t event = thread->get_event();
  195. se_event_wake(event);
  196. it = it->next;
  197. }
  198. }
  199. CTrustThread * CTrustThreadPool::_acquire_thread()
  200. {
  201. //try to get tcs from thread cache
  202. se_thread_id_t thread_id = get_thread_id();
  203. CTrustThread *trust_thread = get_bound_thread(thread_id);
  204. if(NULL != trust_thread)
  205. {
  206. return trust_thread;
  207. }
  208. //try get tcs from free list;
  209. trust_thread = get_free_thread();
  210. //if there is no free tcs, collect useless tcs.
  211. if(NULL == trust_thread)
  212. {
  213. if(!garbage_collect())
  214. return NULL;
  215. //get tcs from free list again.
  216. trust_thread = get_free_thread();
  217. assert(NULL != trust_thread);
  218. }
  219. //we have got a free tcs. add the tcs to thread cache
  220. bind_thread(thread_id, trust_thread);
  221. return trust_thread;
  222. }
  223. CTrustThread * CTrustThreadPool::acquire_thread()
  224. {
  225. LockGuard lock(&m_thread_mutex);
  226. CTrustThread *trust_thread = NULL;
  227. trust_thread = _acquire_thread();
  228. if(trust_thread)
  229. trust_thread->increase_ref();
  230. return trust_thread;
  231. }
  232. //Do nothing for bind mode, the tcs is always bound to a thread.
  233. void CTrustThreadPool::release_thread(CTrustThread * const trust_thread)
  234. {
  235. LockGuard lock(&m_thread_mutex);
  236. trust_thread->decrease_ref();
  237. return;
  238. }
  239. //The return value stand for the number of free trust thread.
  240. int CThreadPoolBindMode::garbage_collect()
  241. {
  242. int nr_free = 0;
  243. //if free list is NULL, recycle tcs.
  244. //get thread id set of current process
  245. vector<se_thread_id_t> thread_vector;
  246. get_thread_set(thread_vector);
  247. //walk through thread cache to see if there is any thread that has exited
  248. Node<se_thread_id_t, CTrustThread*>* it = m_thread_list, *pre = NULL, *tmp = NULL;
  249. while(it != NULL)
  250. {
  251. se_thread_id_t thread_id = it->key;
  252. //if the thread has exited
  253. if(FALSE == find_thread(thread_vector, thread_id))
  254. {
  255. //if the reference is not 0, there must be some wrong termination, so we can't recycle such trust thread.
  256. //return to free_tcs list
  257. if(0 == it->value->get_reference())
  258. {
  259. m_free_thread_vector.push_back(it->value);
  260. nr_free++;
  261. }
  262. else
  263. {
  264. //the list only record the pointer of trust thread, so we can delete it first and then erase from map.
  265. delete it->value;
  266. }
  267. tmp = it;
  268. it = it->next;
  269. if (tmp == m_thread_list)
  270. m_thread_list = it;
  271. if (pre != NULL)
  272. pre->next = it;
  273. //remove from thread cache
  274. delete tmp;
  275. }
  276. else
  277. {
  278. pre = it;
  279. it = it->next;
  280. }
  281. }
  282. return nr_free;
  283. }
  284. int CThreadPoolUnBindMode::garbage_collect()
  285. {
  286. int nr_free = 0;
  287. //walk through to free unused trust thread
  288. Node<se_thread_id_t, CTrustThread*>* it = m_thread_list, *pre = NULL, *tmp = NULL;
  289. while(it != NULL)
  290. {
  291. //if the reference is 0, then the trust thread is not in use, so return to free_tcs list
  292. if(0 == it->value->get_reference())
  293. {
  294. m_free_thread_vector.push_back(it->value);
  295. nr_free++;
  296. tmp = it;
  297. it = it->next;
  298. if (tmp == m_thread_list)
  299. m_thread_list = it;
  300. if (pre != NULL)
  301. pre->next = it;
  302. //remove from thread cache
  303. delete tmp;
  304. }
  305. else
  306. {
  307. pre = it;
  308. it = it->next;
  309. }
  310. }
  311. return nr_free;
  312. }