/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */ /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */ /* Copyright (C) 2014 Stony Brook University This file is part of Graphene Library OS. Graphene Library OS is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Graphene Library OS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ /* * db_threading.c * * This file contain APIs to create, exit and yield a thread. */ #include "pal_defs.h" #include "pal_linux_defs.h" #include "pal.h" #include "pal_internal.h" #include "pal_linux.h" #include "pal_error.h" #include "pal_debug.h" #include "api.h" #include #include #include #include #include #include /* default size of a new thread stack */ /* DEP 2/4/17: There is enough stuff allocated on the PAL stack now * that we need two pages in Linux host mode. In SGX mode, * the enclave/non-clave split makes 1 page in/1 out sufficient. */ #define THREAD_STACK_SIZE (pal_state.alloc_align * 2) /* _DkThreadCreate for internal use. Create an internal thread inside the current process. The arguments callback and param specify the starting function and parameters */ int _DkThreadCreate (PAL_HANDLE * handle, int (*callback) (void *), const void * param, int flags) { void * child_stack = NULL; if (_DkVirtualMemoryAlloc(&child_stack, THREAD_STACK_SIZE, 0, PAL_PROT_READ|PAL_PROT_WRITE) < 0) return -PAL_ERROR_NOMEM; /* move child_stack to the top of stack. */ child_stack += THREAD_STACK_SIZE; /* align child_stack to 16 */ child_stack = (void *) ((uintptr_t) child_stack & ~16); int tid = 0; int ret = clone(callback, child_stack, CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SYSVSEM| CLONE_THREAD|CLONE_SIGHAND|CLONE_PTRACE| CLONE_PARENT_SETTID, param, &tid, NULL); if (IS_ERR(ret)) return -PAL_ERROR_DENIED; PAL_HANDLE hdl = malloc(HANDLE_SIZE(thread)); SET_HANDLE_TYPE(hdl, thread); hdl->thread.tid = tid; *handle = hdl; /* _DkThreadAdd(tid); */ return 0; } int _DkThreadDelayExecution (unsigned long * duration) { struct timespec sleeptime; struct timespec remainingtime; long sec = (unsigned long) *duration / 1000000; long microsec = (unsigned long) *duration - (sec * 1000000); sleeptime.tv_sec = sec; sleeptime.tv_nsec = microsec * 1000; int ret = INLINE_SYSCALL(nanosleep, 2, &sleeptime, &remainingtime); if (IS_ERR(ret)) { PAL_NUM remaining = remainingtime.tv_sec * 1000000 + remainingtime.tv_nsec / 1000; *duration -= remaining; return -PAL_ERROR_INTERRUPTED; } return 0; } /* PAL call DkThreadYieldExecution. Yield the execution of the current thread. */ void _DkThreadYieldExecution (void) { INLINE_SYSCALL(sched_yield, 0); } /* _DkThreadExit for internal use: Thread exiting */ void _DkThreadExit (void) { INLINE_SYSCALL(exit, 1, 0); } int _DkThreadResume (PAL_HANDLE threadHandle) { int ret = INLINE_SYSCALL(tgkill, 3, linux_state.pid, threadHandle->thread.tid, SIGCONT); if (IS_ERR(ret)) return -PAL_ERROR_DENIED; return 0; } struct handle_ops thread_ops = { /* nothing */ };