| 1024 | void _photon_thread_stub() asm("_photon_thread_stub"); |
| 1025 | |
| 1026 | thread* thread_create(thread_entry start, void* arg, uint64_t stack_size, |
| 1027 | uint32_t reserved_space, uint64_t flags) { |
| 1028 | if (!stack_size) |
| 1029 | stack_size = DEFAULT_STACK_SIZE; |
| 1030 | if (unlikely((uint64_t)reserved_space > stack_size / 2)) |
| 1031 | LOG_ERROR_RETURN(EINVAL, nullptr, VALUE(reserved_space), "must be <= half of ", VALUE(stack_size)); |
| 1032 | uint64_t FLAGS = THREAD_JOINABLE | THREAD_ENABLE_WORK_STEALING; |
| 1033 | if (unlikely(flags & ~FLAGS)) |
| 1034 | LOG_ERRNO_RETURN(EINVAL, nullptr, "invalid flags", HEX(flags)); |
| 1035 | RunQ rq; |
| 1036 | if (unlikely(!rq.current)) |
| 1037 | LOG_ERROR_RETURN(ENOSYS, nullptr, "Photon not initialized in this vCPU (OS thread)"); |
| 1038 | thread_local uint64_t random_index = 0; |
| 1039 | size_t randomizer = (random_index++ % 512) * 8; |
| 1040 | // stack contains struct, randomizer space, and reserved_space |
| 1041 | size_t least_stack_size = sizeof(thread) + randomizer + 63 + reserved_space; |
| 1042 | // at least a whole page for mprotect |
| 1043 | least_stack_size += PAGE_SIZE; |
| 1044 | // and make sure it's at least 16K and aligned to page size |
| 1045 | least_stack_size = align_up(std::max(16UL * 1024, least_stack_size), PAGE_SIZE); |
| 1046 | stack_size = align_up(stack_size, PAGE_SIZE); |
| 1047 | if (unlikely(stack_size < least_stack_size)) { |
| 1048 | LOG_WARN(VALUE(stack_size), " is less than minimal value `, use the minimal value instead", least_stack_size); |
| 1049 | stack_size = least_stack_size; |
| 1050 | } |
| 1051 | char* ptr = (char*)photon_thread_alloc(stack_size); |
| 1052 | if (unlikely(!ptr)) |
| 1053 | return nullptr; |
| 1054 | uint64_t p = (uint64_t)ptr + stack_size - sizeof(thread) - randomizer; |
| 1055 | p = align_down(p, 64); |
| 1056 | auto th = new ((char*)p) thread; |
| 1057 | th->buf = ptr; |
| 1058 | th->stackful_alloc_top = ptr + PAGE_SIZE; |
| 1059 | th->start = start; |
| 1060 | th->stack_size = stack_size; |
| 1061 | th->arg = arg; |
| 1062 | th->flags = flags; |
| 1063 | auto sp = align_down(p - reserved_space, 64); |
| 1064 | th->stack.init((void*)sp, &_photon_thread_stub, th); |
| 1065 | AtomicRunQ arq(rq); |
| 1066 | th->vcpu = arq.vcpu; |
| 1067 | arq.vcpu->nthreads++; |
| 1068 | arq.insert_tail(th); |
| 1069 | return th; |
| 1070 | } |
| 1071 | |
| 1072 | #if defined(__x86_64__) && defined(__linux__) && defined(ENABLE_MIMIC_VDSO) |
| 1073 | #include <sys/auxv.h> |