123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- /*
- * Copyright (C) 2011-2016 Intel Corporation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
- #include "tcs.h"
- #include "se_trace.h"
- #include "sgx_error.h"
- #include "se_memory.h"
- #include "se_thread.h"
- #include <assert.h>
- extern se_thread_id_t get_thread_id();
- CTrustThread::CTrustThread(tcs_t *tcs, CEnclave* enclave)
- : m_tcs(tcs)
- , m_enclave(enclave)
- , m_reference(0)
- , m_event(NULL)
- {
- memset(&m_tcs_info, 0, sizeof(debug_tcs_info_t));
- m_tcs_info.TCS_address = reinterpret_cast<void*>(tcs);
- m_tcs_info.ocall_frame = 0;
- m_tcs_info.thread_id = 0;
- }
- CTrustThread::~CTrustThread()
- {
- se_event_destroy(m_event);
- m_event = NULL;
- }
- se_handle_t CTrustThread::get_event()
- {
- if (m_event == NULL)
- m_event = se_event_init();
- return m_event;
- }
- void CTrustThread::push_ocall_frame(ocall_frame_t* frame_point)
- {
- frame_point->index = this->get_reference();
- frame_point->pre_last_frame = m_tcs_info.ocall_frame;
- m_tcs_info.ocall_frame = reinterpret_cast<uintptr_t>(frame_point);
- m_tcs_info.thread_id = get_thread_id();
- }
- void CTrustThread::pop_ocall_frame()
- {
- ocall_frame_t* last_ocall_frame = reinterpret_cast<ocall_frame_t*>(m_tcs_info.ocall_frame);
- if (last_ocall_frame)
- {
- m_tcs_info.ocall_frame = last_ocall_frame->pre_last_frame;
- }
- }
- CTrustThreadPool::CTrustThreadPool()
- {
- m_thread_list = NULL;
- }
- CTrustThreadPool::~CTrustThreadPool()
- {
- LockGuard lock(&m_thread_mutex);
- //destroy free tcs list
- for(vector<CTrustThread *>::iterator it=m_free_thread_vector.begin(); it!=m_free_thread_vector.end(); it++)
- {
- delete *it;
- }
- m_free_thread_vector.clear();
- //destroy thread cache
- Node<se_thread_id_t, CTrustThread*>* it = m_thread_list, *tmp = NULL;
- while (it != NULL)
- {
- delete it->value;
- tmp = it;
- it = it->next;
- delete tmp;
- }
- m_thread_list = NULL;
- }
- void get_thread_set(vector<se_thread_id_t> &thread_vector);
- inline int CTrustThreadPool::find_thread(vector<se_thread_id_t> &thread_vector, se_thread_id_t thread_id)
- {
- for(vector<se_thread_id_t>::iterator it=thread_vector.begin(); it!=thread_vector.end(); it++)
- if(*it == thread_id)
- return TRUE;
- return FALSE;
- }
- inline CTrustThread * CTrustThreadPool::get_free_thread()
- {
- if(true == m_free_thread_vector.empty())
- {
- return NULL;
- }
- //if there is free tcs, remove it from free list
- CTrustThread *thread_node = m_free_thread_vector.back();
- m_free_thread_vector.pop_back();
- return thread_node;
- }
- //This tcs policy is bind tcs with one thread.
- int CTrustThreadPool::bind_thread(const se_thread_id_t thread_id, CTrustThread * const trust_thread)
- {
- if (m_thread_list == NULL) {
- m_thread_list = new Node<se_thread_id_t, CTrustThread*>(thread_id, trust_thread);
- } else {
- Node<se_thread_id_t, CTrustThread*>* it = new Node<se_thread_id_t, CTrustThread*>(thread_id, trust_thread);
- if (m_thread_list->InsertNext(it) == false) {
- delete it;
- SE_TRACE(SE_TRACE_WARNING, "trust thread %x is already added to the list\n", trust_thread);
- return FALSE;
- }
- }
- return TRUE;
- }
- CTrustThread * CTrustThreadPool::get_bound_thread(const se_thread_id_t thread_id)
- {
- CTrustThread *trust_thread = NULL;
- Node<se_thread_id_t, CTrustThread*>* it = m_thread_list->Find(thread_id);
- if(it != NULL)
- trust_thread = it->value;
- return trust_thread;
- }
- CTrustThread * CTrustThreadPool::add_thread(tcs_t * const tcs, CEnclave * const enclave)
- {
- CTrustThread *trust_thread = new CTrustThread(tcs, enclave);
- LockGuard lock(&m_thread_mutex);
- //add tcs to free list
- m_free_thread_vector.push_back(trust_thread);
- return trust_thread;
- }
- CTrustThread *CTrustThreadPool::get_bound_thread(const tcs_t *tcs)
- {
- //Since now this function will be call outside, we need get lock to protect map
- LockGuard lock(&m_thread_mutex);
- CTrustThread *trust_thread = NULL;
- if (m_thread_list == NULL)
- return NULL;
- Node<se_thread_id_t, CTrustThread*>* it = m_thread_list;
- while (it != NULL) {
- trust_thread = it->value;
- if(trust_thread->get_tcs() == tcs) {
- return trust_thread;
- }
- it = it->next;
- }
- return NULL;
- }
- void CTrustThreadPool::reset()
- {
- //get lock at the begin of list walk.
- LockGuard lock(&m_thread_mutex);
- //walk through thread cache to free every element;
- Node<se_thread_id_t, CTrustThread*>* it = m_thread_list, *tmp = NULL;
- while(it != NULL)
- {
- tmp = it;
- it = it->next;
- CTrustThread *trust_thread = tmp->value;
- //remove from thread cache
- delete tmp;
- trust_thread->reset_ref();
- m_free_thread_vector.push_back(trust_thread);
- }
- m_thread_list = NULL;
- return;
- }
- void CTrustThreadPool::wake_threads()
- {
- LockGuard lock(&m_thread_mutex);
- Node<se_thread_id_t, CTrustThread*>* it = m_thread_list;
- while (it != NULL) {
- CTrustThread *thread = it->value;
- se_handle_t event = thread->get_event();
- se_event_wake(event);
- it = it->next;
- }
- }
- CTrustThread * CTrustThreadPool::_acquire_thread()
- {
- //try to get tcs from thread cache
- se_thread_id_t thread_id = get_thread_id();
- CTrustThread *trust_thread = get_bound_thread(thread_id);
- if(NULL != trust_thread)
- {
- return trust_thread;
- }
- //try get tcs from free list;
- trust_thread = get_free_thread();
- //if there is no free tcs, collect useless tcs.
- if(NULL == trust_thread)
- {
- if(!garbage_collect())
- return NULL;
- //get tcs from free list again.
- trust_thread = get_free_thread();
- assert(NULL != trust_thread);
- }
- //we have got a free tcs. add the tcs to thread cache
- bind_thread(thread_id, trust_thread);
- return trust_thread;
- }
- CTrustThread * CTrustThreadPool::acquire_thread()
- {
- LockGuard lock(&m_thread_mutex);
- CTrustThread *trust_thread = NULL;
- trust_thread = _acquire_thread();
- if(trust_thread)
- trust_thread->increase_ref();
- return trust_thread;
- }
- //Do nothing for bind mode, the tcs is always bound to a thread.
- void CTrustThreadPool::release_thread(CTrustThread * const trust_thread)
- {
- LockGuard lock(&m_thread_mutex);
- trust_thread->decrease_ref();
- return;
- }
- //The return value stand for the number of free trust thread.
- int CThreadPoolBindMode::garbage_collect()
- {
- int nr_free = 0;
- //if free list is NULL, recycle tcs.
- //get thread id set of current process
- vector<se_thread_id_t> thread_vector;
- get_thread_set(thread_vector);
- //walk through thread cache to see if there is any thread that has exited
- Node<se_thread_id_t, CTrustThread*>* it = m_thread_list, *pre = NULL, *tmp = NULL;
- while(it != NULL)
- {
- se_thread_id_t thread_id = it->key;
- //if the thread has exited
- if(FALSE == find_thread(thread_vector, thread_id))
- {
- //if the reference is not 0, there must be some wrong termination, so we can't recycle such trust thread.
- //return to free_tcs list
- if(0 == it->value->get_reference())
- {
- m_free_thread_vector.push_back(it->value);
- nr_free++;
- }
- else
- {
- //the list only record the pointer of trust thread, so we can delete it first and then erase from map.
- delete it->value;
- }
- tmp = it;
- it = it->next;
- if (tmp == m_thread_list)
- m_thread_list = it;
- if (pre != NULL)
- pre->next = it;
- //remove from thread cache
- delete tmp;
- }
- else
- {
- pre = it;
- it = it->next;
- }
- }
- return nr_free;
- }
- int CThreadPoolUnBindMode::garbage_collect()
- {
- int nr_free = 0;
- //walk through to free unused trust thread
- Node<se_thread_id_t, CTrustThread*>* it = m_thread_list, *pre = NULL, *tmp = NULL;
- while(it != NULL)
- {
- //if the reference is 0, then the trust thread is not in use, so return to free_tcs list
- if(0 == it->value->get_reference())
- {
- m_free_thread_vector.push_back(it->value);
- nr_free++;
- tmp = it;
- it = it->next;
- if (tmp == m_thread_list)
- m_thread_list = it;
- if (pre != NULL)
- pre->next = it;
- //remove from thread cache
- delete tmp;
- }
- else
- {
- pre = it;
- it = it->next;
- }
- }
- return nr_free;
- }
|