diff options
Diffstat (limited to 'src/pal/src/include/pal')
51 files changed, 10585 insertions, 0 deletions
diff --git a/src/pal/src/include/pal/cert.hpp b/src/pal/src/include/pal/cert.hpp new file mode 100644 index 0000000000..77c7f28d1a --- /dev/null +++ b/src/pal/src/include/pal/cert.hpp @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/cert.hpp + +Abstract: + Header file for cert structures + + + +--*/ + +#ifndef _PAL_CERT_HPP_ +#define _PAL_CERT_HPP_ + +#include "corunix.hpp" + +#include <Security/Security.h> + +CorUnix::PAL_ERROR OIDToStr(CSSM_DATA &data, CHAR *&oidStrOut); + +CSSM_RETURN InitCSSMModule(const CSSM_GUID *inGuid, CSSM_SERVICE_TYPE inService, + CSSM_MODULE_HANDLE_PTR outModule); +CSSM_RETURN TermCSSMModule(const CSSM_GUID *inGuid, CSSM_MODULE_HANDLE_PTR inModule); + +#endif // !_PAL_CERT_HPP_ diff --git a/src/pal/src/include/pal/context.h b/src/pal/src/include/pal/context.h new file mode 100644 index 0000000000..5e378942fb --- /dev/null +++ b/src/pal/src/include/pal/context.h @@ -0,0 +1,641 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/context.h + +Abstract: + + Header file for thread context utility functions. + + + +--*/ + +#ifndef _PAL_CONTEXT_H_ +#define _PAL_CONTEXT_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +#include <signal.h> +#include <pthread.h> + +#if !HAVE_MACH_EXCEPTIONS +/* A type to wrap the native context type, which is ucontext_t on some + * platforms and another type elsewhere. */ +#if HAVE_UCONTEXT_T +#include <ucontext.h> + +typedef ucontext_t native_context_t; +#else // HAVE_UCONTEXT_T +#error Native context type is not known on this platform! +#endif // HAVE_UCONTEXT_T +#else // !HAVE_MACH_EXCEPTIONS +#include <mach/kern_return.h> +#include <mach/mach_port.h> +#endif // !HAVE_MACH_EXCEPTIONS else + +#if HAVE___GREGSET_T + +#ifdef BIT64 +#define MCREG_Rbx(mc) ((mc).__gregs[_REG_RBX]) +#define MCREG_Rcx(mc) ((mc).__gregs[_REG_RCX]) +#define MCREG_Rdx(mc) ((mc).__gregs[_REG_RDX]) +#define MCREG_Rsi(mc) ((mc).__gregs[_REG_RSI]) +#define MCREG_Rdi(mc) ((mc).__gregs[_REG_RDI]) +#define MCREG_Rbp(mc) ((mc).__gregs[_REG_RBP]) +#define MCREG_Rax(mc) ((mc).__gregs[_REG_RAX]) +#define MCREG_Rip(mc) ((mc).__gregs[_REG_RIP]) +#define MCREG_Rsp(mc) ((mc).__gregs[_REG_RSP]) +#define MCREG_SegCs(mc) ((mc).__gregs[_REG_CS]) +#define MCREG_SegSs(mc) ((mc).__gregs[_REG_SS]) +#define MCREG_R8(mc) ((mc).__gregs[_REG_R8]) +#define MCREG_R9(mc) ((mc).__gregs[_REG_R9]) +#define MCREG_R10(mc) ((mc).__gregs[_REG_R10]) +#define MCREG_R11(mc) ((mc).__gregs[_REG_R11]) +#define MCREG_R12(mc) ((mc).__gregs[_REG_R12]) +#define MCREG_R13(mc) ((mc).__gregs[_REG_R13]) +#define MCREG_R14(mc) ((mc).__gregs[_REG_R14]) +#define MCREG_R15(mc) ((mc).__gregs[_REG_R15]) +#define MCREG_EFlags(mc) ((mc).__gregs[_REG_RFLAGS]) + +#define FPREG_Xmm(uc, index) *(M128A*)&(((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_xmm[index]) + +#define FPREG_St(uc, index) *(M128A*)&(((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_87_ac[index]) + +#define FPREG_ControlWord(uc) (((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_cw) +#define FPREG_StatusWord(uc) (((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_sw) +#define FPREG_TagWord(uc) (((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_tw) +#define FPREG_ErrorOffset(uc) (*(DWORD*) &(((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_ip)) +#define FPREG_ErrorSelector(uc) *((WORD*) &(((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_ip) + 2) +#define FPREG_DataOffset(uc) (*(DWORD*) &(((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_dp)) +#define FPREG_DataSelector(uc) *((WORD*) &(((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_dp) + 2) +#define FPREG_MxCsr(uc) (((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_mxcsr) +#define FPREG_MxCsr_Mask(uc) (((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_mxcsr_mask) + +#else // BIT64 + +#define MCREG_Ebx(mc) ((mc).__gregs[_REG_EBX]) +#define MCREG_Ecx(mc) ((mc).__gregs[_REG_ECX]) +#define MCREG_Edx(mc) ((mc).__gregs[_REG_EDX]) +#define MCREG_Esi(mc) ((mc).__gregs[_REG_ESI]) +#define MCREG_Edi(mc) ((mc).__gregs[_REG_EDI]) +#define MCREG_Ebp(mc) ((mc).__gregs[_REG_EBP]) +#define MCREG_Eax(mc) ((mc).__gregs[_REG_EAX]) +#define MCREG_Eip(mc) ((mc).__gregs[_REG_EIP]) +#define MCREG_Esp(mc) ((mc).__gregs[_REG_ESP]) +#define MCREG_SegCs(mc) ((mc).__gregs[_REG_CS]) +#define MCREG_SegSs(mc) ((mc).__gregs[_REG_SS]) +#define MCREG_EFlags(mc) ((mc).__gregs[_REG_RFLAGS]) + +#endif // BIT64 + +#elif HAVE_GREGSET_T + +#ifdef BIT64 +#define MCREG_Rbx(mc) ((mc).gregs[REG_RBX]) +#define MCREG_Rcx(mc) ((mc).gregs[REG_RCX]) +#define MCREG_Rdx(mc) ((mc).gregs[REG_RDX]) +#define MCREG_Rsi(mc) ((mc).gregs[REG_RSI]) +#define MCREG_Rdi(mc) ((mc).gregs[REG_RDI]) +#define MCREG_Rbp(mc) ((mc).gregs[REG_RBP]) +#define MCREG_Rax(mc) ((mc).gregs[REG_RAX]) +#define MCREG_Rip(mc) ((mc).gregs[REG_RIP]) +#define MCREG_Rsp(mc) ((mc).gregs[REG_RSP]) +#define MCREG_SegCs(mc) (*(WORD*)&((mc).gregs[REG_CSGSFS])) +#define MCREG_R8(mc) ((mc).gregs[REG_R8]) +#define MCREG_R9(mc) ((mc).gregs[REG_R9]) +#define MCREG_R10(mc) ((mc).gregs[REG_R10]) +#define MCREG_R11(mc) ((mc).gregs[REG_R11]) +#define MCREG_R12(mc) ((mc).gregs[REG_R12]) +#define MCREG_R13(mc) ((mc).gregs[REG_R13]) +#define MCREG_R14(mc) ((mc).gregs[REG_R14]) +#define MCREG_R15(mc) ((mc).gregs[REG_R15]) + +#define FPREG_Fpstate(uc) ((uc)->uc_mcontext.fpregs) +#define FPREG_Xmm(uc, index) *(M128A*)&(FPREG_Fpstate(uc)->_xmm[index]) + +#define FPREG_St(uc, index) *(M128A*)&(FPREG_Fpstate(uc)->_st[index]) + +#define FPREG_ControlWord(uc) (FPREG_Fpstate(uc)->cwd) +#define FPREG_StatusWord(uc) (FPREG_Fpstate(uc)->swd) +#define FPREG_TagWord(uc) (FPREG_Fpstate(uc)->ftw) +#define FPREG_ErrorOffset(uc) *(DWORD*)&(FPREG_Fpstate(uc)->rip) +#define FPREG_ErrorSelector(uc) *(((WORD*)&(FPREG_Fpstate(uc)->rip)) + 2) +#define FPREG_DataOffset(uc) *(DWORD*)&(FPREG_Fpstate(uc)->rdp) +#define FPREG_DataSelector(uc) *(((WORD*)&(FPREG_Fpstate(uc)->rdp)) + 2) +#define FPREG_MxCsr(uc) (FPREG_Fpstate(uc)->mxcsr) +#define FPREG_MxCsr_Mask(uc) (FPREG_Fpstate(uc)->mxcr_mask) + +///////////////////// +// Extended state + +inline _fpx_sw_bytes *FPREG_FpxSwBytes(const ucontext_t *uc) +{ + // Bytes 464..511 in the FXSAVE format are available for software to use for any purpose. In this case, they are used to + // indicate information about extended state. + _ASSERTE(reinterpret_cast<UINT8 *>(&FPREG_Fpstate(uc)->padding[12]) - reinterpret_cast<UINT8 *>(FPREG_Fpstate(uc)) == 464); + + _ASSERTE(FPREG_Fpstate(uc) != nullptr); + + return reinterpret_cast<_fpx_sw_bytes *>(&FPREG_Fpstate(uc)->padding[12]); +} + +inline UINT32 FPREG_ExtendedSize(const ucontext_t *uc) +{ + _ASSERTE(FPREG_FpxSwBytes(uc)->magic1 == FP_XSTATE_MAGIC1); + return FPREG_FpxSwBytes(uc)->extended_size; +} + +inline bool FPREG_HasExtendedState(const ucontext_t *uc) +{ + // See comments in /usr/include/x86_64-linux-gnu/asm/sigcontext.h for info on how to detect if extended state is present + static_assert_no_msg(FP_XSTATE_MAGIC2_SIZE == sizeof(UINT32)); + + if (FPREG_FpxSwBytes(uc)->magic1 != FP_XSTATE_MAGIC1) + { + return false; + } + + UINT32 extendedSize = FPREG_ExtendedSize(uc); + if (extendedSize < sizeof(_xstate)) + { + return false; + } + + _ASSERTE(extendedSize >= FP_XSTATE_MAGIC2_SIZE); + return *reinterpret_cast<UINT32 *>(reinterpret_cast<UINT8 *>(FPREG_Fpstate(uc)) + (extendedSize - FP_XSTATE_MAGIC2_SIZE)) + == FP_XSTATE_MAGIC2; +} + +inline void *FPREG_Xstate_Ymmh(const ucontext_t *uc) +{ + static_assert_no_msg(sizeof(reinterpret_cast<_xstate *>(FPREG_Fpstate(uc))->ymmh.ymmh_space) == 16 * 16); + _ASSERTE(FPREG_HasExtendedState(uc)); + + return reinterpret_cast<_xstate *>(FPREG_Fpstate(uc))->ymmh.ymmh_space; +} + +///////////////////// + +#else // BIT64 + +#define MCREG_Ebx(mc) ((mc).gregs[REG_EBX]) +#define MCREG_Ecx(mc) ((mc).gregs[REG_ECX]) +#define MCREG_Edx(mc) ((mc).gregs[REG_EDX]) +#define MCREG_Esi(mc) ((mc).gregs[REG_ESI]) +#define MCREG_Edi(mc) ((mc).gregs[REG_EDI]) +#define MCREG_Ebp(mc) ((mc).gregs[REG_EBP]) +#define MCREG_Eax(mc) ((mc).gregs[REG_EAX]) +#define MCREG_Eip(mc) ((mc).gregs[REG_EIP]) +#define MCREG_Esp(mc) ((mc).gregs[REG_ESP]) +#define MCREG_SegCs(mc) ((mc).gregs[REG_CS]) +#define MCREG_SegSs(mc) ((mc).gregs[REG_SS]) + +#endif // BIT64 + +#define MCREG_EFlags(mc) ((mc).gregs[REG_EFL]) + +#else // HAVE_GREGSET_T + +#ifdef BIT64 + +#if defined(_ARM64_) +#define MCREG_X0(mc) ((mc).regs[0]) +#define MCREG_X1(mc) ((mc).regs[1]) +#define MCREG_X2(mc) ((mc).regs[2]) +#define MCREG_X3(mc) ((mc).regs[3]) +#define MCREG_X4(mc) ((mc).regs[4]) +#define MCREG_X5(mc) ((mc).regs[5]) +#define MCREG_X6(mc) ((mc).regs[6]) +#define MCREG_X7(mc) ((mc).regs[7]) +#define MCREG_X8(mc) ((mc).regs[8]) +#define MCREG_X9(mc) ((mc).regs[9]) +#define MCREG_X10(mc) ((mc).regs[10]) +#define MCREG_X11(mc) ((mc).regs[11]) +#define MCREG_X12(mc) ((mc).regs[12]) +#define MCREG_X13(mc) ((mc).regs[13]) +#define MCREG_X14(mc) ((mc).regs[14]) +#define MCREG_X15(mc) ((mc).regs[15]) +#define MCREG_X16(mc) ((mc).regs[16]) +#define MCREG_X17(mc) ((mc).regs[17]) +#define MCREG_X18(mc) ((mc).regs[18]) +#define MCREG_X19(mc) ((mc).regs[19]) +#define MCREG_X20(mc) ((mc).regs[20]) +#define MCREG_X21(mc) ((mc).regs[21]) +#define MCREG_X22(mc) ((mc).regs[22]) +#define MCREG_X23(mc) ((mc).regs[23]) +#define MCREG_X24(mc) ((mc).regs[24]) +#define MCREG_X25(mc) ((mc).regs[25]) +#define MCREG_X26(mc) ((mc).regs[26]) +#define MCREG_X27(mc) ((mc).regs[27]) +#define MCREG_X28(mc) ((mc).regs[28]) +#define MCREG_Fp(mc) ((mc).regs[29]) +#define MCREG_Lr(mc) ((mc).regs[30]) + +#define MCREG_Sp(mc) ((mc).sp) +#define MCREG_Pc(mc) ((mc).pc) +#define MCREG_PState(mc) ((mc).pstate) +#define MCREG_Cpsr(mc) ((mc).cpsr) +#else + // For FreeBSD, as found in x86/ucontext.h +#define MCREG_Rbp(mc) ((mc).mc_rbp) +#define MCREG_Rip(mc) ((mc).mc_rip) +#define MCREG_Rsp(mc) ((mc).mc_rsp) +#define MCREG_Rsi(mc) ((mc).mc_rsi) +#define MCREG_Rdi(mc) ((mc).mc_rdi) +#define MCREG_Rbx(mc) ((mc).mc_rbx) +#define MCREG_Rdx(mc) ((mc).mc_rdx) +#define MCREG_Rcx(mc) ((mc).mc_rcx) +#define MCREG_Rax(mc) ((mc).mc_rax) +#define MCREG_R8(mc) ((mc).mc_r8) +#define MCREG_R9(mc) ((mc).mc_r9) +#define MCREG_R10(mc) ((mc).mc_r10) +#define MCREG_R11(mc) ((mc).mc_r11) +#define MCREG_R12(mc) ((mc).mc_r12) +#define MCREG_R13(mc) ((mc).mc_r13) +#define MCREG_R14(mc) ((mc).mc_r14) +#define MCREG_R15(mc) ((mc).mc_r15) +#define MCREG_EFlags(mc) ((mc).mc_rflags) +#define MCREG_SegCs(mc) ((mc).mc_cs) + + // from x86/fpu.h: struct __envxmm64 +#define FPSTATE(uc) ((savefpu*)((uc)->uc_mcontext.mc_fpstate)) +#define FPREG_ControlWord(uc) FPSTATE(uc)->sv_env.en_cw +#define FPREG_StatusWord(uc) FPSTATE(uc)->sv_env.en_sw +#define FPREG_TagWord(uc) FPSTATE(uc)->sv_env.en_tw +#define FPREG_MxCsr(uc) FPSTATE(uc)->sv_env.en_mxcsr +#define FPREG_MxCsr_Mask(uc) FPSTATE(uc)->sv_env.en_mxcsr_mask +#define FPREG_ErrorOffset(uc) *(DWORD*) &(FPSTATE(uc)->sv_env.en_rip) +#define FPREG_ErrorSelector(uc) *((WORD*) &(FPSTATE(uc)->sv_env.en_rip) + 2) +#define FPREG_DataOffset(uc) *(DWORD*) &(FPSTATE(uc)->sv_env.en_rdp) +#define FPREG_DataSelector(uc) *((WORD*) &(FPSTATE(uc)->sv_env.en_rdp) + 2) + +#define FPREG_Xmm(uc, index) *(M128A*) &(FPSTATE(uc)->sv_xmm[index]) +#define FPREG_St(uc, index) *(M128A*) &(FPSTATE(uc)->sv_fp[index].fp_acc) +#endif + +#else // BIT64 + +#if defined(_ARM_) + +#define MCREG_R0(mc) ((mc).arm_r0) +#define MCREG_R1(mc) ((mc).arm_r1) +#define MCREG_R2(mc) ((mc).arm_r2) +#define MCREG_R3(mc) ((mc).arm_r3) +#define MCREG_R4(mc) ((mc).arm_r4) +#define MCREG_R5(mc) ((mc).arm_r5) +#define MCREG_R6(mc) ((mc).arm_r6) +#define MCREG_R7(mc) ((mc).arm_r7) +#define MCREG_R8(mc) ((mc).arm_r8) +#define MCREG_R9(mc) ((mc).arm_r9) +#define MCREG_R10(mc) ((mc).arm_r10) +#define MCREG_R11(mc) ((mc).arm_fp) +#define MCREG_R12(mc) ((mc).arm_ip) +#define MCREG_Sp(mc) ((mc).arm_sp) +#define MCREG_Lr(mc) ((mc).arm_lr) +#define MCREG_Pc(mc) ((mc).arm_pc) +#define MCREG_Cpsr(mc) ((mc).arm_cpsr) + +#elif defined(_X86_) + +#define MCREG_Ebx(mc) ((mc).mc_ebx) +#define MCREG_Ecx(mc) ((mc).mc_ecx) +#define MCREG_Edx(mc) ((mc).mc_edx) +#define MCREG_Esi(mc) ((mc).mc_esi) +#define MCREG_Edi(mc) ((mc).mc_edi) +#define MCREG_Ebp(mc) ((mc).mc_ebp) +#define MCREG_Eax(mc) ((mc).mc_eax) +#define MCREG_Eip(mc) ((mc).mc_eip) +#define MCREG_SegCs(mc) ((mc).mc_cs) +#define MCREG_EFlags(mc) ((mc).mc_eflags) +#define MCREG_Esp(mc) ((mc).mc_esp) +#define MCREG_SegSs(mc) ((mc).mc_ss) + +#else +#error "Unsupported arch" +#endif + +#endif // BIT64 + +#endif // HAVE_GREGSET_T + + +#if HAVE_PT_REGS + +#ifdef BIT64 +#define PTREG_Rbx(ptreg) ((ptreg).rbx) +#define PTREG_Rcx(ptreg) ((ptreg).rcx) +#define PTREG_Rdx(ptreg) ((ptreg).rdx) +#define PTREG_Rsi(ptreg) ((ptreg).rsi) +#define PTREG_Rdi(ptreg) ((ptreg).rdi) +#define PTREG_Rbp(ptreg) ((ptreg).rbp) +#define PTREG_Rax(ptreg) ((ptreg).rax) +#define PTREG_Rip(ptreg) ((ptreg).rip) +#define PTREG_SegCs(ptreg) ((ptreg).cs) +#define PTREG_SegSs(ptreg) ((ptreg).ss) +#define PTREG_Rsp(ptreg) ((ptreg).rsp) +#define PTREG_R8(ptreg) ((ptreg).r8) +#define PTREG_R9(ptreg) ((ptreg).r9) +#define PTREG_R10(ptreg) ((ptreg).r10) +#define PTREG_R11(ptreg) ((ptreg).r11) +#define PTREG_R12(ptreg) ((ptreg).r12) +#define PTREG_R13(ptreg) ((ptreg).r13) +#define PTREG_R14(ptreg) ((ptreg).r14) +#define PTREG_R15(ptreg) ((ptreg).r15) + +#else // BIT64 + +#if defined(_ARM_) +#define PTREG_R0(ptreg) ((ptreg).uregs[0]) +#define PTREG_R1(ptreg) ((ptreg).uregs[1]) +#define PTREG_R2(ptreg) ((ptreg).uregs[2]) +#define PTREG_R3(ptreg) ((ptreg).uregs[3]) +#define PTREG_R4(ptreg) ((ptreg).uregs[4]) +#define PTREG_R5(ptreg) ((ptreg).uregs[5]) +#define PTREG_R6(ptreg) ((ptreg).uregs[6]) +#define PTREG_R7(ptreg) ((ptreg).uregs[7]) +#define PTREG_R8(ptreg) ((ptreg).uregs[8]) +#define PTREG_R9(ptreg) ((ptreg).uregs[9]) +#define PTREG_R10(ptreg) ((ptreg).uregs[10]) +#define PTREG_R11(ptreg) ((ptreg).uregs[11]) +#define PTREG_R12(ptreg) ((ptreg).uregs[12]) +#define PTREG_Sp(ptreg) ((ptreg).uregs[13]) +#define PTREG_Lr(ptreg) ((ptreg).uregs[14]) +#define PTREG_Pc(ptreg) ((ptreg).uregs[15]) +#define PTREG_Cpsr(ptreg) ((ptreg).uregs[16]) +#elif defined(_X86_) +#define PTREG_Ebx(ptreg) ((ptreg).ebx) +#define PTREG_Ecx(ptreg) ((ptreg).ecx) +#define PTREG_Edx(ptreg) ((ptreg).edx) +#define PTREG_Esi(ptreg) ((ptreg).esi) +#define PTREG_Edi(ptreg) ((ptreg).edi) +#define PTREG_Ebp(ptreg) ((ptreg).ebp) +#define PTREG_Eax(ptreg) ((ptreg).eax) +#define PTREG_Eip(ptreg) ((ptreg).eip) +#define PTREG_SegCs(ptreg) ((ptreg).xcs) +#define PTREG_SegSs(ptreg) ((ptreg).xss) +#define PTREG_Esp(ptreg) ((ptreg).esp) +#else +#error "Unsupported arch" +#endif + +#endif // BIT64 + + +#define PTREG_EFlags(ptreg) ((ptreg).eflags) + +#endif // HAVE_PT_REGS + + + +#if HAVE_BSD_REGS_T + +#ifndef BSD_REGS_STYLE +#error "struct reg" has unrecognized format +#endif + +#ifdef BIT64 + +#define BSDREG_Rbx(reg) BSD_REGS_STYLE(reg,RBX,rbx) +#define BSDREG_Rcx(reg) BSD_REGS_STYLE(reg,RCX,rcx) +#define BSDREG_Rdx(reg) BSD_REGS_STYLE(reg,RDX,rdx) +#define BSDREG_Rsi(reg) BSD_REGS_STYLE(reg,RSI,rsi) +#define BSDREG_Rdi(reg) BSD_REGS_STYLE(reg,RDI,rdi) +#define BSDREG_Rbp(reg) BSD_REGS_STYLE(reg,RBP,rbp) +#define BSDREG_Rax(reg) BSD_REGS_STYLE(reg,RAX,rax) +#define BSDREG_Rip(reg) BSD_REGS_STYLE(reg,RIP,rip) +#define BSDREG_SegCs(reg) BSD_REGS_STYLE(reg,CS,cs) +#define BSDREG_SegSs(reg) BSD_REGS_STYLE(reg,SS,ss) +#define BSDREG_Rsp(reg) BSD_REGS_STYLE(reg,RSP,rsp) +#define BSDREG_R8(reg) BSD_REGS_STYLE(reg,R8,r8) +#define BSDREG_R9(reg) BSD_REGS_STYLE(reg,R9,r9) +#define BSDREG_R10(reg) BSD_REGS_STYLE(reg,R10,r10) +#define BSDREG_R11(reg) BSD_REGS_STYLE(reg,R11,r11) +#define BSDREG_R12(reg) BSD_REGS_STYLE(reg,R12,r12) +#define BSDREG_R13(reg) BSD_REGS_STYLE(reg,R13,r13) +#define BSDREG_R14(reg) BSD_REGS_STYLE(reg,R14,r14) +#define BSDREG_R15(reg) BSD_REGS_STYLE(reg,R15,r15) +#define BSDREG_EFlags(reg) BSD_REGS_STYLE(reg,RFLAGS,rflags) + +#else // BIT64 + +#define BSDREG_Ebx(reg) BSD_REGS_STYLE(reg,EBX,ebx) +#define BSDREG_Ecx(reg) BSD_REGS_STYLE(reg,ECX,ecx) +#define BSDREG_Edx(reg) BSD_REGS_STYLE(reg,EDX,edx) +#define BSDREG_Esi(reg) BSD_REGS_STYLE(reg,ESI,esi) +#define BSDREG_Edi(reg) BSD_REGS_STYLE(reg,EDI,edi) +#define BSDREG_Ebp(reg) BSD_REGS_STYLE(reg,EDP,ebp) +#define BSDREG_Eax(reg) BSD_REGS_STYLE(reg,EAX,eax) +#define BSDREG_Eip(reg) BSD_REGS_STYLE(reg,EIP,eip) +#define BSDREG_SegCs(reg) BSD_REGS_STYLE(reg,CS,cs) +#define BSDREG_EFlags(reg) BSD_REGS_STYLE(reg,EFLAGS,eflags) +#define BSDREG_Esp(reg) BSD_REGS_STYLE(reg,ESP,esp) +#define BSDREG_SegSs(reg) BSD_REGS_STYLE(reg,SS,ss) + +#endif // BIT64 + +#endif // HAVE_BSD_REGS_T + +inline static DWORD64 CONTEXTGetPC(LPCONTEXT pContext) +{ +#if defined(_AMD64_) + return pContext->Rip; +#elif defined(_ARM64_) || defined(_ARM_) + return pContext->Pc; +#else +#error don't know how to get the program counter for this architecture +#endif +} + +inline static void CONTEXTSetPC(LPCONTEXT pContext, DWORD64 pc) +{ +#if defined(_AMD64_) + pContext->Rip = pc; +#elif defined(_ARM64_) || defined(_ARM_) + pContext->Pc = pc; +#else +#error don't know how to set the program counter for this architecture +#endif +} + +/*++ +Function : + CONTEXT_CaptureContext + + Captures the context of the caller. + The returned context is suitable for performing + a virtual unwind. + +Parameters : + LPCONTEXT lpContext : new context + +--*/ +void +CONTEXT_CaptureContext( + LPCONTEXT lpContext + ); + +/*++ +Function : + CONTEXT_SetThreadContext + + Processor-dependent implementation of SetThreadContext + +Parameters : + HANDLE hThread : thread whose context is to be set + CONTEXT *lpContext : new context + +Return value : + TRUE on success, FALSE on failure + +--*/ +BOOL +CONTEXT_SetThreadContext( + DWORD dwProcessId, + pthread_t self, + CONST CONTEXT *lpContext + ); + +/*++ +Function : + CONTEXT_GetThreadContext + + Processor-dependent implementation of GetThreadContext + +Parameters : + HANDLE hThread : thread whose context is to retrieved + LPCONTEXT lpContext : destination for thread's context + +Return value : + TRUE on success, FALSE on failure + +--*/ +BOOL +CONTEXT_GetThreadContext( + DWORD dwProcessId, + pthread_t self, + LPCONTEXT lpContext); + +#if HAVE_MACH_EXCEPTIONS +/*++ +Function: + CONTEXT_GetThreadContextFromPort + + Helper for GetThreadContext that uses a mach_port +--*/ +kern_return_t +CONTEXT_GetThreadContextFromPort( + mach_port_t Port, + LPCONTEXT lpContext); + +/*++ +Function: + SetThreadContextOnPort + + Helper for CONTEXT_SetThreadContext +--*/ +kern_return_t +CONTEXT_SetThreadContextOnPort( + mach_port_t Port, + IN CONST CONTEXT *lpContext); + +/*++ +Function: + GetThreadContextFromThreadState + + Helper for mach exception support +--*/ +void +CONTEXT_GetThreadContextFromThreadState( + thread_state_flavor_t stateFlavor, + thread_state_t threadState, + LPCONTEXT lpContext); + +#else // HAVE_MACH_EXCEPTIONS +/*++ +Function : + CONTEXTToNativeContext + + Converts a CONTEXT record to a native context. + +Parameters : + CONST CONTEXT *lpContext : CONTEXT to convert, including + flags that determine which registers are valid in + lpContext and which ones to set in native + native_context_t *native : native context to fill in + +Return value : + None + +--*/ +void CONTEXTToNativeContext(CONST CONTEXT *lpContext, native_context_t *native); + +/*++ +Function : + CONTEXTFromNativeContext + + Converts a native context to a CONTEXT record. + +Parameters : + const native_context_t *native : native context to convert + LPCONTEXT lpContext : CONTEXT to fill in + ULONG contextFlags : flags that determine which registers are valid in + native and which ones to set in lpContext + +Return value : + None + +--*/ +void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContext, + ULONG contextFlags); + +/*++ +Function : + GetNativeContextPC + + Returns the program counter from the native context. + +Parameters : + const native_context_t *context : native context + +Return value : + The program counter from the native context. + +--*/ +LPVOID GetNativeContextPC(const native_context_t *context); + +/*++ +Function : + CONTEXTGetExceptionCodeForSignal + + Translates signal and context information to a Win32 exception code. + +Parameters : + const siginfo_t *siginfo : signal information from a signal handler + const native_context_t *context : context information + +Return value : + The Win32 exception code that corresponds to the signal and context + information. + +--*/ +DWORD CONTEXTGetExceptionCodeForSignal(const siginfo_t *siginfo, + const native_context_t *context); + +#endif // HAVE_MACH_EXCEPTIONS else + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // _PAL_CONTEXT_H_ diff --git a/src/pal/src/include/pal/corunix.hpp b/src/pal/src/include/pal/corunix.hpp new file mode 100644 index 0000000000..e9e9503ed3 --- /dev/null +++ b/src/pal/src/include/pal/corunix.hpp @@ -0,0 +1,1359 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + corunix.hpp + +Abstract: + + Internal interface and object definitions + + + +--*/ + +#ifndef _CORUNIX_H +#define _CORUNIX_H + +#include "palinternal.h" + +namespace CorUnix +{ + typedef DWORD PAL_ERROR; + + // + // Forward declarations for classes defined in other headers + // + + class CPalThread; + + // + // Forward declarations for items in this header + // + + class CObjectType; + class IPalObject; + + // + // A simple counted string class. Using counted strings + // allows for some optimizations when searching for a matching string. + // + + class CPalString + { + protected: + + const WCHAR *m_pwsz; // NULL terminated + + // + // Length of string, not including terminating NULL + // + + DWORD m_dwStringLength; + + // + // Length of buffer backing string; must be at least 1+dwStringLength + // + + DWORD m_dwMaxLength; + + public: + + CPalString() + : + m_pwsz(NULL), + m_dwStringLength(0), + m_dwMaxLength(0) + { + }; + + CPalString( + const WCHAR *pwsz + ) + { + SetString(pwsz); + }; + + void + SetString( + const WCHAR *pwsz + ) + { + SetStringWithLength(pwsz, PAL_wcslen(pwsz)); + }; + + void + SetStringWithLength( + const WCHAR *pwsz, + DWORD dwStringLength + ) + { + m_pwsz = pwsz; + m_dwStringLength = dwStringLength; + m_dwMaxLength = m_dwStringLength + 1; + + }; + + PAL_ERROR + CopyString( + CPalString *psSource + ); + + void + FreeBuffer(); + + const WCHAR * + GetString() + { + return m_pwsz; + }; + + DWORD + GetStringLength() + { + return m_dwStringLength; + }; + + DWORD + GetMaxLength() + { + return m_dwMaxLength; + }; + + }; + + // + // Signature of the cleanup routine that is to be called for an object + // type when: + // 1) The object's refcount drops to 0 + // 2) A process is shutting down + // 3) A process has released all local references to the object + // + // The cleanup routine must only cleanup the object's shared state + // when the last parameter (fCleanupSharedSate) is TRUE. When + // fCleanupSharedState is FALSE the cleanup routine must not attempt + // to access the shared data for the object, as another process may + // have already deleted it. ($$REIVEW -- would someone ever need access + // to the shared data in order to cleanup process local state?) + // + // When the third paramter (fShutdown) is TRUE the process is in + // the act of exiting. The cleanup routine should not perform any + // unnecessary cleanup operations (e.g., closing file descriptors, + // since the OS will automatically close them when the process exits) + // in this situation. + // + + typedef void (*OBJECTCLEANUPROUTINE) ( + CPalThread *, // pThread + IPalObject *, // pObjectToCleanup + bool, // fShutdown + bool // fCleanupSharedState + ); + + // + // Signature of the initialization routine that is to be called + // when the first reference within a process to an existing + // object comes into existence. This routine is responsible for + // initializing the object's process local data, based on the + // immutable and shared data. The thread that this routine is + // called on holds an implicit read lock on the shared data. + // + + typedef PAL_ERROR (*OBJECTINITROUTINE) ( + CPalThread *, // pThread + CObjectType *, // pObjectType + void *, // pImmutableData + void *, // pSharedData + void * // pProcessLocalData + ); + + enum PalObjectTypeId + { + otiAutoResetEvent = 0, + otiManualResetEvent, + otiMutex, + otiNamedMutex, + otiSemaphore, + otiFile, + otiFileMapping, + otiSocket, + otiProcess, + otiThread, + otiIOCompletionPort, + ObjectTypeIdCount // This entry must come last in the enumeration + }; + + // + // There should be one instance of CObjectType for each supported + // type in a process; this allows for pointer equality tests + // to be used (though in general it's probably better to use + // checks based on the type ID). All members of this structure are + // immutable. + // + // The data size members control how much space will be allocated for + // instances of this object. Any or all of those members may be 0. + // + // dwSupportedAccessRights is the mask of valid access bits for this + // object type. Supported generic rights should not be included in + // this member. + // + // The generic access rights mapping (structure TBD) defines how the + // supported generic access rights (e.g., GENERIC_READ) map to the + // specific access rights for this object type. + // + // If instances of this object may have a security descriptor set on + // them eSecuritySupport should be set to SecuritySupported. If the OS can + // persist security information for the object type (as would be the case + // for, say, files) eSecurityPersistence should be set to + // OSPersistedSecurityInfo. + // + // If the object may have a name eObjectNameSupport should be + // ObjectCanHaveName. A named object can be opened in more than one + // process. + // + // If it is possible to duplicate a handle to an object across process + // boundaries then eHandleDuplicationSupport should be set to + // CrossProcessDuplicationAllowed. Note that it is possible to have + // an object type where eObjectNameSupport is ObjectCanHaveName and + // eHandleDuplicationSupport is LocalDuplicationOnly. For these object + // types an unnamed object instance will only have references from + // the creating process. + // + // If the object may be waited on eSynchronizationSupport should be + // WaitableObject. (Note that this implies that object type supports + // the SYNCHRONIZE access right.) + // + // The remaining members describe the wait-object semantics for the + // object type when eSynchronizationSupport is WaitableObject: + // + // * eSignalingSemantics: SingleTransitionObject for objects that, once + // they transition to the signaled state, can never transition back to + // the unsignaled state (e.g., processes and threads) + // + // * eThreadReleaseSemantics: if ThreadReleaseAltersSignalCount the object's + // signal count is decremented when a waiting thread is released; otherwise, + // the signal count is not modified (as is desired for a manual reset event). + // Must be ThreadReleaseHasNoSideEffects if eSignalingSemantics is + // SingleTransitionObject + // + // * eOwnershipSemantics: OwnershipTracked only for mutexes, for which the + // previous two items must also ObjectCanBeUnsignaled and + // ThreadReleaseAltersSignalCount. + // + + class CObjectType + { + public: + + enum SecuritySupport + { + SecuritySupported, + SecurityNotSupported + }; + + enum SecurityPersistence + { + OSPersistedSecurityInfo, + SecurityInfoNotPersisted + }; + + enum ObjectNameSupport + { + ObjectCanHaveName, + UnnamedObject + }; + + enum HandleDuplicationSupport + { + CrossProcessDuplicationAllowed, + LocalDuplicationOnly + }; + + enum SynchronizationSupport + { + WaitableObject, + UnwaitableObject + }; + + enum SignalingSemantics + { + ObjectCanBeUnsignaled, + SingleTransitionObject, + SignalingNotApplicable + }; + + enum ThreadReleaseSemantics + { + ThreadReleaseAltersSignalCount, + ThreadReleaseHasNoSideEffects, + ThreadReleaseNotApplicable + }; + + enum OwnershipSemantics + { + OwnershipTracked, + NoOwner, + OwnershipNotApplicable + }; + + private: + + // + // Array that maps object type IDs to the corresponding + // CObjectType instance + // + + static CObjectType* s_rgotIdMapping[]; + + PalObjectTypeId m_eTypeId; + OBJECTCLEANUPROUTINE m_pCleanupRoutine; + OBJECTINITROUTINE m_pInitRoutine; + DWORD m_dwImmutableDataSize; + DWORD m_dwProcessLocalDataSize; + DWORD m_dwSharedDataSize; + DWORD m_dwSupportedAccessRights; + // Generic access rights mapping + SecuritySupport m_eSecuritySupport; + SecurityPersistence m_eSecurityPersistence; + ObjectNameSupport m_eObjectNameSupport; + HandleDuplicationSupport m_eHandleDuplicationSupport; + SynchronizationSupport m_eSynchronizationSupport; + SignalingSemantics m_eSignalingSemantics; + ThreadReleaseSemantics m_eThreadReleaseSemantics; + OwnershipSemantics m_eOwnershipSemantics; + + public: + + CObjectType( + PalObjectTypeId eTypeId, + OBJECTCLEANUPROUTINE pCleanupRoutine, + OBJECTINITROUTINE pInitRoutine, + DWORD dwImmutableDataSize, + DWORD dwProcessLocalDataSize, + DWORD dwSharedDataSize, + DWORD dwSupportedAccessRights, + SecuritySupport eSecuritySupport, + SecurityPersistence eSecurityPersistence, + ObjectNameSupport eObjectNameSupport, + HandleDuplicationSupport eHandleDuplicationSupport, + SynchronizationSupport eSynchronizationSupport, + SignalingSemantics eSignalingSemantics, + ThreadReleaseSemantics eThreadReleaseSemantics, + OwnershipSemantics eOwnershipSemantics + ) + : + m_eTypeId(eTypeId), + m_pCleanupRoutine(pCleanupRoutine), + m_pInitRoutine(pInitRoutine), + m_dwImmutableDataSize(dwImmutableDataSize), + m_dwProcessLocalDataSize(dwProcessLocalDataSize), + m_dwSharedDataSize(dwSharedDataSize), + m_dwSupportedAccessRights(dwSupportedAccessRights), + m_eSecuritySupport(eSecuritySupport), + m_eSecurityPersistence(eSecurityPersistence), + m_eObjectNameSupport(eObjectNameSupport), + m_eHandleDuplicationSupport(eHandleDuplicationSupport), + m_eSynchronizationSupport(eSynchronizationSupport), + m_eSignalingSemantics(eSignalingSemantics), + m_eThreadReleaseSemantics(eThreadReleaseSemantics), + m_eOwnershipSemantics(eOwnershipSemantics) + { + s_rgotIdMapping[eTypeId] = this; + }; + + static + CObjectType * + GetObjectTypeById( + PalObjectTypeId otid + ) + { + return s_rgotIdMapping[otid]; + }; + + PalObjectTypeId + GetId( + void + ) + { + return m_eTypeId; + }; + + OBJECTCLEANUPROUTINE + GetObjectCleanupRoutine( + void + ) + { + return m_pCleanupRoutine; + }; + + OBJECTINITROUTINE + GetObjectInitRoutine( + void + ) + { + return m_pInitRoutine; + }; + + DWORD + GetImmutableDataSize( + void + ) + { + return m_dwImmutableDataSize; + }; + + DWORD + GetProcessLocalDataSize( + void + ) + { + return m_dwProcessLocalDataSize; + }; + + DWORD + GetSharedDataSize( + void + ) + { + return m_dwSharedDataSize; + }; + + DWORD + GetSupportedAccessRights( + void + ) + { + return m_dwSupportedAccessRights; + }; + + // Generic access rights mapping + + SecuritySupport + GetSecuritySupport( + void + ) + { + return m_eSecuritySupport; + }; + + SecurityPersistence + GetSecurityPersistence( + void + ) + { + return m_eSecurityPersistence; + }; + + ObjectNameSupport + GetObjectNameSupport( + void + ) + { + return m_eObjectNameSupport; + }; + + HandleDuplicationSupport + GetHandleDuplicationSupport( + void + ) + { + return m_eHandleDuplicationSupport; + }; + + SynchronizationSupport + GetSynchronizationSupport( + void + ) + { + return m_eSynchronizationSupport; + }; + + SignalingSemantics + GetSignalingSemantics( + void + ) + { + return m_eSignalingSemantics; + }; + + ThreadReleaseSemantics + GetThreadReleaseSemantics( + void + ) + { + return m_eThreadReleaseSemantics; + }; + + OwnershipSemantics + GetOwnershipSemantics( + void + ) + { + return m_eOwnershipSemantics; + }; + }; + + class CAllowedObjectTypes + { + private: + + bool m_rgfAllowedTypes[ObjectTypeIdCount]; + + public: + + bool + IsTypeAllowed(PalObjectTypeId eTypeId); + + // + // Constructor for multiple allowed types + // + + CAllowedObjectTypes( + PalObjectTypeId rgAllowedTypes[], + DWORD dwAllowedTypeCount + ); + + // + // Single allowed type constructor + // + + CAllowedObjectTypes( + PalObjectTypeId eAllowedType + ); + + // + // Allow all types or no types constructor + // + + CAllowedObjectTypes( + bool fAllowAllObjectTypes + ) + { + for (DWORD dw = 0; dw < ObjectTypeIdCount; dw += 1) + { + m_rgfAllowedTypes[dw] = fAllowAllObjectTypes; + } + }; + + ~CAllowedObjectTypes() + { + }; + }; + + // + // Attributes for a given object instance. If the object does not have + // a name the sObjectName member should be zero'd out. If the default + // security attributes are desired then pSecurityAttributes should + // be NULL. + // + + class CObjectAttributes + { + public: + + CPalString sObjectName; + LPSECURITY_ATTRIBUTES pSecurityAttributes; + + CObjectAttributes( + const WCHAR *pwszObjectName, + LPSECURITY_ATTRIBUTES pSecurityAttributes_ + ) + : + pSecurityAttributes(pSecurityAttributes_) + { + if (NULL != pwszObjectName) + { + sObjectName.SetString(pwszObjectName); + } + }; + + CObjectAttributes() + : + pSecurityAttributes(NULL) + { + }; + }; + + // + // ISynchStateController is used to modify any object's synchronization + // state. It is intended to be used from within the APIs exposed for + // various objects (e.g., SetEvent, ReleaseMutex, etc.). + // + // Each ISynchStateController instance implicitly holds what should be + // viewed as the global dispatcher lock, and as such should be released + // as quickly as possible. An ISynchStateController instance is bound to + // the thread that requested it; it may not be passed to a different + // thread. + // + + class ISynchStateController + { + public: + + virtual + PAL_ERROR + GetSignalCount( + LONG *plSignalCount + ) = 0; + + virtual + PAL_ERROR + SetSignalCount( + LONG lNewCount + ) = 0; + + virtual + PAL_ERROR + IncrementSignalCount( + LONG lAmountToIncrement + ) = 0; + + virtual + PAL_ERROR + DecrementSignalCount( + LONG lAmountToDecrement + ) = 0; + + // + // The following two routines may only be used for object types + // where eOwnershipSemantics is OwnershipTracked (i.e., mutexes). + // + + // + // SetOwner is intended to be used in the implementation of + // CreateMutex when bInitialOwner is TRUE. It must be called + // before the new object instance is registered with the + // handle manager. Any other call to this method is an error. + // + + virtual + PAL_ERROR + SetOwner( + CPalThread *pNewOwningThread + ) = 0; + + // + // DecrementOwnershipCount returns an error if the object + // is unowned, or if the thread this controller is bound to + // is not the owner of the object. + // + + virtual + PAL_ERROR + DecrementOwnershipCount( + void + ) = 0; + + virtual + void + ReleaseController( + void + ) = 0; + }; + + // + // ISynchWaitController is used to indicate a thread's desire to wait for + // an object (which possibly includes detecting instances where the wait + // can be satisfied without blocking). It is intended to be used by object + // wait function (WaitForSingleObject, etc.). + // + // Each ISynchWaitController instance implicitly holds what should be + // viewed as the global dispatcher lock, and as such should be released + // as quickly as possible. An ISynchWaitController instance is bound to + // the thread that requested it; it may not be passed to a different + // thread. + // + // A thread may hold multiple ISynchWaitController instances + // simultaneously. + // + + enum WaitType + { + SingleObject, + MultipleObjectsWaitOne, + MultipleObjectsWaitAll + }; + + class ISynchWaitController + { + public: + + // + // CanThreadWaitWithoutBlocking informs the caller if a wait + // operation may succeed immediately, but does not actually + // alter any object state. ReleaseWaitingThreadWithoutBlocking + // alters the object state, and will return an error if it is + // not possible for the wait to be immediately satisfied. + // + + virtual + PAL_ERROR + CanThreadWaitWithoutBlocking( + bool *pfCanWaitWithoutBlocking, // OUT + bool *pfAbandoned + ) = 0; + + virtual + PAL_ERROR + ReleaseWaitingThreadWithoutBlocking( + ) = 0; + + // + // dwIndex is intended for MultipleObjectsWaitOne situations. The + // index for the object that becomes signaled and satisfies the + // wait will be returned in the call to BlockThread. + // + + virtual + PAL_ERROR + RegisterWaitingThread( + WaitType eWaitType, + DWORD dwIndex, + bool fAltertable + ) = 0; + + // + // Why is there no unregister waiting thread routine? Unregistration + // is the responsibility of the synchronization provider, not the + // implementation of the wait object routines. (I can be convinced + // that this isn't the best approach, though...) + // + + virtual + void + ReleaseController( + void + ) = 0; + }; + + enum LockType + { + ReadLock, + WriteLock + }; + + class IDataLock + { + public: + + // + // If a thread obtains a write lock but does not actually + // modify any data it should set fDataChanged to FALSE. If + // a thread obtain a read lock and does actually modify any + // data it should be taken out back and shot. + // + + virtual + void + ReleaseLock( + CPalThread *pThread, // IN, OPTIONAL + bool fDataChanged + ) = 0; + }; + + // + // The following two enums are part of the local object + // optimizations + // + + enum ObjectDomain + { + ProcessLocalObject, + SharedObject + }; + + enum WaitDomain + { + LocalWait, // All objects in the wait set are local to this process + MixedWait, // Some objects are local; some are shared + SharedWait // All objects in the wait set are shared + }; + + class IPalObject + { + public: + + virtual + CObjectType * + GetObjectType( + VOID + ) = 0; + + virtual + CObjectAttributes * + GetObjectAttributes( + VOID + ) = 0; + + virtual + PAL_ERROR + GetImmutableData( + void **ppvImmutableData // OUT + ) = 0; + + // + // The following two routines obtain either a read or write + // lock on the data in question. If a thread needs to examine + // both process-local and shared data simultaneously it must obtain + // the shared data first. A thread may not hold data locks + // on two different objects at the same time. + // + + virtual + PAL_ERROR + GetProcessLocalData( + CPalThread *pThread, // IN, OPTIONAL + LockType eLockRequest, + IDataLock **ppDataLock, // OUT + void **ppvProcessLocalData // OUT + ) = 0; + + virtual + PAL_ERROR + GetSharedData( + CPalThread *pThread, // IN, OPTIONAL + LockType eLockRequest, + IDataLock **ppDataLock, // OUT + void **ppvSharedData // OUT + ) = 0; + + // + // The following two routines obtain the global dispatcher lock. + // If a thread needs to make use of a synchronization interface + // and examine object data it must obtain the synchronization + // interface first. A thread is allowed to hold synchronization + // interfaces for multiple objects at the same time if it obtains + // all of the interfaces through a single call (see IPalSynchronizationManager + // below). + // + // The single-call restriction allows the underlying implementation + // to possibly segement the global dispatcher lock. If this restriction + // were not in place (i.e., if a single thread were allowed to call + // GetSynchXXXController for multiple objects) no such segmentation + // would be possible as there would be no way know in what order a + // thread would choose to obtain the controllers. + // + // Note: this design precludes simultaneous acquisition of both + // the state and wait controller for an object but there are + // currently no places where doing so would be necessary. + // + + virtual + PAL_ERROR + GetSynchStateController( + CPalThread *pThread, // IN, OPTIONAL + ISynchStateController **ppStateController // OUT + ) = 0; + + virtual + PAL_ERROR + GetSynchWaitController( + CPalThread *pThread, // IN, OPTIONAL + ISynchWaitController **ppWaitController // OUT + ) = 0; + + virtual + DWORD + AddReference( + void + ) = 0; + + virtual + DWORD + ReleaseReference( + CPalThread *pThread + ) = 0; + + // + // This routine is mainly intended for the synchronization + // manager. The promotion / process synch lock must be held + // before calling this routine. + // + + virtual + ObjectDomain + GetObjectDomain( + void + ) = 0; + + // + // This routine is only for use by the synchronization manager + // (specifically, for GetSynch*ControllersForObjects). The + // caller must have acquired the appropriate lock before + // (whatever exactly that must be) before calling this routine. + // + + virtual + PAL_ERROR + GetObjectSynchData( + VOID **ppvSynchData // OUT + ) = 0; + + }; + + class IPalProcess + { + public: + virtual + DWORD + GetProcessID( + void + ) = 0; + }; + + class IPalObjectManager + { + public: + + // + // Object creation (e.g., what is done by CreateEvent) is a two step + // process. First, the new object is allocated and the initial + // properties set (e.g., initially signaled). Next, the object is + // registered, yielding a handle. If an object of the same name + // and appropriate type already existed the returned handle will refer + // to the previously existing object, and the newly allocated object + // will have been thrown away. + // + // (The two phase process minimizes the amount of time that any + // namespace locks need to be held. While some wasted work may be + // done in the existing object case that work only impacts the calling + // thread. Checking first for existence and then allocating and + // initializing on failure requires any namespace lock to be held for + // a much longer period of time, impacting the entire system.) + // + + virtual + PAL_ERROR + AllocateObject( + CPalThread *pThread, // IN, OPTIONAL + CObjectType *pType, + CObjectAttributes *pAttributes, + IPalObject **ppNewObject // OUT + ) = 0; + + // + // After calling RegisterObject pObjectToRegister is no + // longer valid. If successful there are two references + // on the returned object -- one for the handle, and one + // for the instance returned in ppRegisteredObject. The + // caller, therefore, is responsible for releasing the + // latter. + // + // For named object pAllowedTypes specifies what type of + // existing objects can be returned in ppRegisteredObjects. + // This is primarily intended for CreateEvent, so that + // a ManualResetEvent can be returned when attempting to + // register an AutoResetEvent (and vice-versa). pAllowedTypes + // must include the type of pObjectToRegister. + // + + virtual + PAL_ERROR + RegisterObject( + CPalThread *pThread, // IN, OPTIONAL + IPalObject *pObjectToRegister, + CAllowedObjectTypes *pAllowedTypes, + DWORD dwRightsRequested, + HANDLE *pHandle, // OUT + IPalObject **ppRegisteredObject // OUT + ) = 0; + + // + // LocateObject is used for OpenXXX routines. ObtainHandleForObject + // is needed for the OpenXXX routines and DuplicateHandle. + // + + virtual + PAL_ERROR + LocateObject( + CPalThread *pThread, // IN, OPTIONAL + CPalString *psObjectToLocate, + CAllowedObjectTypes *pAllowedTypes, + IPalObject **ppObject // OUT + ) = 0; + + // + // pProcessForHandle is to support cross-process handle + // duplication. It only needs to be specified when acquiring + // a handle meant for use in a different process; it should + // be left NULL when acquiring a handle for the current + // process. + // + + virtual + PAL_ERROR + ObtainHandleForObject( + CPalThread *pThread, // IN, OPTIONAL + IPalObject *pObject, + DWORD dwRightsRequested, + bool fInheritHandle, + IPalProcess *pProcessForHandle, // IN, OPTIONAL + HANDLE *pNewHandle // OUT + ) = 0; + + virtual + PAL_ERROR + RevokeHandle( + CPalThread *pThread, // IN, OPTIONAL + HANDLE hHandleToRevoke + ) = 0; + + // + // The Reference routines are called to obtain the + // object that a handle refers to. The caller must + // specify the rights that the handle must hold for + // the operation that it is about to perform. The caller + // is responsible for converting generic rights to specific + // rights. The caller must also specify what object types + // are permissible for the object. + // + // The returned object[s], on success, are referenced, + // and the caller is responsible for releasing those references + // when appropriate. + // + + virtual + PAL_ERROR + ReferenceObjectByHandle( + CPalThread *pThread, // IN, OPTIONAL + HANDLE hHandleToReference, + CAllowedObjectTypes *pAllowedTypes, + DWORD dwRightsRequired, + IPalObject **ppObject // OUT + ) = 0; + + // + // This routine is intended for WaitForMultipleObjects[Ex] + // + + virtual + PAL_ERROR + ReferenceMultipleObjectsByHandleArray( + CPalThread *pThread, // IN, OPTIONAL + HANDLE rghHandlesToReference[], + DWORD dwHandleCount, + CAllowedObjectTypes *pAllowedTypes, + DWORD dwRightsRequired, + IPalObject *rgpObjects[] // OUT + ) = 0; + + // + // This routine is for cross-process handle duplication. + // + + virtual + PAL_ERROR + ReferenceObjectByForeignHandle( + CPalThread *pThread, // IN, OPTIONAL + HANDLE hForeignHandle, + IPalProcess *pForeignProcess, + CAllowedObjectTypes *pAllowedTypes, + DWORD dwRightsRequired, + IPalObject **ppObject // OUT + ) = 0; + + }; + + extern IPalObjectManager *g_pObjectManager; + + enum ThreadWakeupReason + { + WaitSucceeded, + Alerted, + MutexAbondoned, + WaitTimeout, + WaitFailed + }; + + class IPalSynchronizationManager + { + public: + + // + // A thread calls BlockThread to put itself to sleep after it has + // registered itself with the objects it is to wait on. A thread + // need not have registered with any objects, as would occur in + // the implementation of Sleep[Ex]. + // + // Needless to say a thread must not be holding any PAL locks + // directly or implicitly (e.g., by holding a reference to a + // synchronization controller) when it calls this method. + // + + virtual + PAL_ERROR + BlockThread( + CPalThread *pCurrentThread, + DWORD dwTimeout, + bool fAlertable, + bool fIsSleep, + ThreadWakeupReason *peWakeupReason, // OUT + DWORD *pdwSignaledObject // OUT + ) = 0; + + virtual + PAL_ERROR + AbandonObjectsOwnedByThread( + CPalThread *pCallingThread, + CPalThread *pTargetThread + ) = 0; + + virtual + PAL_ERROR + QueueUserAPC( + CPalThread *pThread, + CPalThread *pTargetThread, + PAPCFUNC pfnAPC, + ULONG_PTR dwData + ) = 0; + + virtual + bool + AreAPCsPending( + CPalThread *pThread + ) = 0; + + virtual + PAL_ERROR + DispatchPendingAPCs( + CPalThread *pThread + ) = 0; + + virtual + PAL_ERROR + SendTerminationRequestToWorkerThread() = 0; + + // + // This routine is primarily meant for use by WaitForMultipleObjects[Ex]. + // The caller must individually release each of the returned controller + // interfaces. + // + + virtual + PAL_ERROR + GetSynchWaitControllersForObjects( + CPalThread *pThread, + IPalObject *rgObjects[], + DWORD dwObjectCount, + ISynchWaitController *rgControllers[] + ) = 0; + + virtual + PAL_ERROR + GetSynchStateControllersForObjects( + CPalThread *pThread, + IPalObject *rgObjects[], + DWORD dwObjectCount, + ISynchStateController *rgControllers[] + ) = 0; + + // + // These following routines are meant for use only by IPalObject + // implementations. The first two routines are used to + // allocate and free an object's synchronization state; the third + // is called during object promotion. + // + + virtual + PAL_ERROR + AllocateObjectSynchData( + CObjectType *pObjectType, + ObjectDomain eObjectDomain, + VOID **ppvSynchData // OUT + ) = 0; + + virtual + void + FreeObjectSynchData( + CObjectType *pObjectType, + ObjectDomain eObjectDomain, + VOID *pvSynchData + ) = 0; + + virtual + PAL_ERROR + PromoteObjectSynchData( + CPalThread *pThread, + VOID *pvLocalSynchData, + VOID **ppvSharedSynchData // OUT + ) = 0; + + // + // The next two routines provide access to the process-wide + // synchronization lock + // + + virtual + void + AcquireProcessLock( + CPalThread *pThread + ) = 0; + + virtual + void + ReleaseProcessLock( + CPalThread *pThread + ) = 0; + + // + // The final routines are used by IPalObject::GetSynchStateController + // and IPalObject::GetSynchWaitController + // + + virtual + PAL_ERROR + CreateSynchStateController( + CPalThread *pThread, // IN, OPTIONAL + CObjectType *pObjectType, + VOID *pvSynchData, + ObjectDomain eObjectDomain, + ISynchStateController **ppStateController // OUT + ) = 0; + + virtual + PAL_ERROR + CreateSynchWaitController( + CPalThread *pThread, // IN, OPTIONAL + CObjectType *pObjectType, + VOID *pvSynchData, + ObjectDomain eObjectDomain, + ISynchWaitController **ppWaitController // OUT + ) = 0; + }; + + extern IPalSynchronizationManager *g_pSynchronizationManager; + + class IFileTransactionLock + { + public: + + // + // Called when the transaction completes (which includes + // error completions, or the outright failure to queue + // the transaction). + // + + virtual + void + ReleaseLock() = 0; + }; + + class IFileLockController + { + public: + + // + // A transaction lock is acquired before a read or write + // operation, and released when that operation completes. + // The lock is not tied to the calling thread, since w/ + // asynch file IO the completion may occur on a different + // thread. + // + + enum FileTransactionLockType + { + ReadLock, + WriteLock + }; + + virtual + PAL_ERROR + GetTransactionLock( + CPalThread *pThread, // IN, OPTIONAL + FileTransactionLockType eLockType, + DWORD dwOffsetLow, + DWORD dwOffsetHigh, + DWORD nNumberOfBytesToLockLow, + DWORD nNumberOfBytesToLockHigh, + IFileTransactionLock **ppTransactionLock // OUT + ) = 0; + + enum FileLockExclusivity + { + ExclusiveFileLock, + SharedFileLock + }; + + enum FileLockWaitMode + { + FailImmediately, + WaitForLockAcquisition + }; + + virtual + PAL_ERROR + CreateFileLock( + CPalThread *pThread, // IN, OPTIONAL + DWORD dwOffsetLow, + DWORD dwOffsetHigh, + DWORD nNumberOfBytesToLockLow, + DWORD nNumberOfBytesToLockHigh, + FileLockExclusivity eFileLockExclusivity, + FileLockWaitMode eFileLockWaitMode + ) = 0; + + virtual + PAL_ERROR + ReleaseFileLock( + CPalThread *pThread, // IN, OPTIONAL + DWORD dwOffsetLow, + DWORD dwOffsetHigh, + DWORD nNumberOfBytesToUnlockLow, + DWORD nNumberOfBytesToUnlockHigh + ) = 0; + + // + // ReleaseController should be called from the file object's + // cleanup routine. It must always be called, even if fShutdown is + // TRUE or fCleanupSharedState is FALSE. + // + + virtual + void + ReleaseController() = 0; + }; + + class IFileLockManager + { + public: + + // + // GetLockControllerForFile should be called by CreateFile. + // It will fail if the requested access rights and share + // mode are not compatible with existing lock controllers + // for the file. + // + + virtual + PAL_ERROR + GetLockControllerForFile( + CPalThread *pThread, // IN, OPTIONAL + LPCSTR szFileName, + DWORD dwAccessRights, + DWORD dwShareMode, + IFileLockController **ppLockController // OUT + ) = 0; + + // + // Gets the share mode for the file + // (returns SHARE_MODE_NOT_INITIALIZED if file lock controller + // not found) + // + virtual + PAL_ERROR + GetFileShareModeForFile( + LPCSTR szFileName, + DWORD* pdwShareMode) = 0; + }; + + extern IFileLockManager *g_pFileLockManager; +} + +#endif // _CORUNIX_H + diff --git a/src/pal/src/include/pal/corunix.inl b/src/pal/src/include/pal/corunix.inl new file mode 100644 index 0000000000..ab0ac70462 --- /dev/null +++ b/src/pal/src/include/pal/corunix.inl @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + + +--*/ + +#ifndef _CORUNIX_INL +#define _CORUNIX_INL + +#include "corunix.hpp" +#include "dbgmsg.h" + +namespace CorUnix +{ + + bool CAllowedObjectTypes::IsTypeAllowed(PalObjectTypeId eTypeId) + { + _ASSERTE(eTypeId != ObjectTypeIdCount); + return m_rgfAllowedTypes[eTypeId]; + }; + + CAllowedObjectTypes::CAllowedObjectTypes( + PalObjectTypeId rgAllowedTypes[], + DWORD dwAllowedTypeCount + ) + { + ZeroMemory(m_rgfAllowedTypes, sizeof(m_rgfAllowedTypes)); + for (DWORD dw = 0; dw < dwAllowedTypeCount; dw += 1) + { + _ASSERTE(rgAllowedTypes[dw] != ObjectTypeIdCount); + m_rgfAllowedTypes[rgAllowedTypes[dw]] = TRUE; + } + }; + + CAllowedObjectTypes::CAllowedObjectTypes( + PalObjectTypeId eAllowedType + ) + { + ZeroMemory(m_rgfAllowedTypes, sizeof(m_rgfAllowedTypes)); + + _ASSERTE(eAllowedType != ObjectTypeIdCount); + m_rgfAllowedTypes[eAllowedType] = TRUE; + }; +} + +#endif // _CORUNIX_H + diff --git a/src/pal/src/include/pal/critsect.h b/src/pal/src/include/pal/critsect.h new file mode 100644 index 0000000000..50dea95bc5 --- /dev/null +++ b/src/pal/src/include/pal/critsect.h @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/critsect.h + +Abstract: + + Header file for the critical sections functions. + + + +--*/ + +#ifndef _PAL_CRITSECT_H_ +#define _PAL_CRITSECT_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +VOID InternalInitializeCriticalSection(CRITICAL_SECTION *pcs); +VOID InternalDeleteCriticalSection(CRITICAL_SECTION *pcs); + +/* The following PALCEnterCriticalSection and PALCLeaveCriticalSection + functions are intended to provide CorUnix's InternalEnterCriticalSection + and InternalLeaveCriticalSection functionalities to legacy C code, + which has no knowledge of CPalThread, classes and namespaces. +*/ +VOID PALCEnterCriticalSection(CRITICAL_SECTION *pcs); +VOID PALCLeaveCriticalSection(CRITICAL_SECTION *pcs); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* _PAL_CRITSECT_H_ */ + diff --git a/src/pal/src/include/pal/cruntime.h b/src/pal/src/include/pal/cruntime.h new file mode 100644 index 0000000000..65bf33c952 --- /dev/null +++ b/src/pal/src/include/pal/cruntime.h @@ -0,0 +1,247 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/cruntime.h + +Abstract: + + Header file for C runtime utility functions. + + + +--*/ + +#ifndef _PAL_CRUNTIME_H_ +#define _PAL_CRUNTIME_H_ + +#include <string.h> +#include <stdarg.h> +#include <pthread.h> + +#ifdef __cplusplus +typedef char16_t wchar_16; // __wchar_16 (which is defined in palinternal.h) is defined as wchar_16_cpp. + +extern "C" +{ +#endif // __cplusplus + +typedef enum +{ + PFF_NONE = 0, + PFF_MINUS = 1, + PFF_POUND = 2, + PFF_ZERO = 4, + PFF_SPACE = 8, + PFF_PLUS = 16 +}PRINTF_FORMAT_FLAGS; + +typedef enum +{ + WIDTH_DEFAULT = -1, + WIDTH_STAR = -2, /* e.g. "%*.10s" */ + WIDTH_INVALID = -3 /* e.g. "%*3.10s" */ +}WIDTH_FLAGS; + +typedef enum +{ + PRECISION_DEFAULT = -1, + PRECISION_STAR = -2, /* e.g. "%10.*s" */ + PRECISION_DOT = -3, /* e.g. "%10.s" */ + PRECISION_INVALID = -4 /* e.g. "%10.*3s" */ +}PRECISION_FLAGS; + +typedef enum +{ + PFF_PREFIX_DEFAULT = -1, + PFF_PREFIX_SHORT = 1, + PFF_PREFIX_LONG = 2, + PFF_PREFIX_LONGLONG = 3, + PFF_PREFIX_LONG_W = 4 +}PRINTF_PREFIXES; + +typedef enum +{ + PFF_TYPE_DEFAULT = -1, + PFF_TYPE_CHAR = 1, + PFF_TYPE_STRING = 2, + PFF_TYPE_WSTRING = 3, + PFF_TYPE_INT = 4, + PFF_TYPE_P = 5, + PFF_TYPE_N = 6, + PFF_TYPE_FLOAT = 7 +}PRINTF_TYPES; + +typedef enum +{ + SCANF_PREFIX_SHORT = 1, + SCANF_PREFIX_LONG = 2, + SCANF_PREFIX_LONGLONG = 3 +}SCANF_PREFIXES; + +typedef enum +{ + SCANF_TYPE_CHAR = 1, + SCANF_TYPE_STRING = 2, + SCANF_TYPE_INT = 3, + SCANF_TYPE_N = 4, + SCANF_TYPE_FLOAT = 5, + SCANF_TYPE_BRACKETS = 6, + SCANF_TYPE_SPACE = 7 +}SCANF_TYPES; + +/******************************************************************************* +Function: + Internal_AddPaddingA + +Parameters: + Out + - buffer to place padding and given string (In) + Count + - maximum chars to be copied so as not to overrun given buffer + In + - string to place into (Out) accompanied with padding + Padding + - number of padding chars to add + Flags + - padding style flags (PRINTF_FORMAT_FLAGS) +*******************************************************************************/ +BOOL Internal_AddPaddingA(LPSTR *Out, INT Count, LPSTR In, INT Padding, INT Flags); + +/******************************************************************************* +Function: + PAL_printf_arg_remover + +Parameters: + ap + - pointer to the va_list from which to remove arguments + Width + - the width of the current format option + Precision + - the precision of the current format option + Type + - the type of the argument for the current format option + Prefix + - the prefix for the current format option +*******************************************************************************/ +void PAL_printf_arg_remover(va_list *ap, INT Width, INT Precision, INT Type, INT Prefix); + +/*++ +Function: + Silent_PAL_vsnprintf + +See MSDN doc. +--*/ +INT Silent_PAL_vsnprintf(LPSTR Buffer, INT Count, LPCSTR Format, va_list ap); + +/*++ +Function: + Silent_PAL_vfprintf + +See MSDN doc. +--*/ +int Silent_PAL_vfprintf(PAL_FILE *stream, const char *format, va_list ap); + + + +/*++ +Function: + PAL_iswlower + +See MSDN + +--*/ +int __cdecl PAL_iswlower( wchar_16 c ); + + +/*++ +Function: + PAL_iswalpha + +See MSDN + +--*/ +int __cdecl PAL_iswalpha( wchar_16 c ); + +#if HAVE_COREFOUNDATION +/*-- +Function: + PAL_iswblank + +Returns TRUE if c is a Win32 "blank" character. +--*/ +int __cdecl PAL_iswblank(wchar_16 c); + +/*-- +Function: + PAL_iswcntrl + +Returns TRUE if c is a control character. +--*/ +int __cdecl PAL_iswcntrl(wchar_16 c); + +/*-- +Function: + PAL_iswcntrl + +Returns TRUE if c is a control character. +--*/ +int __cdecl PAL_iswpunct(wchar_16 c); +#endif // HAVE_COREFOUNDATION + +/*++ + +struct PAL_FILE. +Used to mimic the behavior of windows. +fwrite under windows can set the ferror flag, +under BSD fwrite doesn't. +--*/ +struct _FILE +{ + FILE * bsdFilePtr; /* The BSD file to be passed to the + functions needing it. */ + + INT PALferrorCode; /* The ferror code that fwrite sets, + incase of error */ + + BOOL bTextMode; /* Boolean variable to denote that the + fle is opened in text/binary mode*/ +#if UNGETC_NOT_RETURN_EOF + BOOL bWriteOnlyMode;/* Boolean variable to denote that the + fle is opened in write-only mode*/ +#endif //UNGETC_NOT_RETURN_EOF +}; + +enum CRT_ERROR_CODES +{ + PAL_FILE_NOERROR = 0, + PAL_FILE_ERROR +}; + +/* Global variables storing the std streams. Defined in cruntime/file.c. */ +extern PAL_FILE PAL_Stdout; +extern PAL_FILE PAL_Stdin; +extern PAL_FILE PAL_Stderr; + +/*++ + +Functio: + + CRTInitStdStreams. + + Initilizes the standard streams. + Returns TRUE on success, FALSE otherwise. +--*/ +BOOL CRTInitStdStreams( void ); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* _PAL_CRUNTIME_H_ */ diff --git a/src/pal/src/include/pal/cs.hpp b/src/pal/src/include/pal/cs.hpp new file mode 100644 index 0000000000..76e268566b --- /dev/null +++ b/src/pal/src/include/pal/cs.hpp @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/////////////////////////////////////////////////////////////////////////////// +// +// File: +// cs.cpp +// +// Purpose: +// Header file for critical sections implementation +// + +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _PAL_CS_HPP +#define _PAL_CS_HPP + +#include "corunix.hpp" +#include "critsect.h" + +namespace CorUnix +{ + void CriticalSectionSubSysInitialize(void); + + void InternalInitializeCriticalSectionAndSpinCount( + PCRITICAL_SECTION pCriticalSection, + DWORD dwSpinCount, + bool fInternal); + + void InternalEnterCriticalSection( + CPalThread *pThread, + CRITICAL_SECTION *pcs + ); + + void InternalLeaveCriticalSection( + CPalThread *pThread, + CRITICAL_SECTION *pcs + ); + + bool InternalTryEnterCriticalSection( + CPalThread * pThread, + PCRITICAL_SECTION pCriticalSection); + +#ifdef _DEBUG + void PALCS_ReportStatisticalData(void); + void PALCS_DumpCSList(); +#endif // _DEBUG + +} + +#endif // _PAL_CS_HPP + diff --git a/src/pal/src/include/pal/dbgmsg.h b/src/pal/src/include/pal/dbgmsg.h new file mode 100644 index 0000000000..7a49fc0ad6 --- /dev/null +++ b/src/pal/src/include/pal/dbgmsg.h @@ -0,0 +1,628 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/dbgmsg.h + +Abstract: + Header file for Debug Message utilities. Output macros, type definitions, + extern variables. See overview section below for usage details. + +--*/ + +/* +Overview of Debug Message utilities + +Use debug channels to selectively output information to the console. + +Available macros : + + - SET_DEFAULT_DEBUG_CHANNEL + + This defines the channel to use with the macros TRACE, ERROR, etc + Use this macro once at the beginning of your source file. + (impl. details : this declares a constant static variable defdbgchan and + sets it to the apropriate channel) + + usage : SET_DEFAULT_DEBUG_CHANNEL(somechannel); + + - TRACE, ENTRY, WARN, ERROR, DBGOUT + + Use this to output debug messages to the default debug channel (set with + SET_DEFAULT_DEBUG_CHANNEL). Messages will only be output if the channel is + active for the specified level. + + usage : TRACE("printf format string", params...); + + - TRACE_, ENTRY_, WARN_, ERROR_, DBGOUT_ + + Use this to autput debug messages to a channel other than the default. + + usage : TRACE_(someotherchannel)("printf format string",params...); + ^ ^^ ^ + don't forget the double set of parentheses! + +Available channels : + PAL : PAL-specific functionalities (PAL_Initialize, etc.) + LOADER : Loading API (LoadLibrary, etc); loader application + HANDLE : Handle manager (CloseHandle, etc.) + SHMEM : Shared Memory functions (for IPC) + PROCESS : Process related APIs + THREAD : Threading mechanism + EXCEPT : Structured Exception Handling functions + CRT : PAL implementation of the C Runtime Library functions + UNICODE : Unicode support API + ARCH : platform-dependent stuff + SYNC : Management of synchronization objects + FILE : File I/O API + VIRTUAL : Virtual memory and File mapping + MEM : Memory management (except Virtual* stuff) + SOCKET : WINSOCK implementation + DEBUG : Debugging API (ReadProcessMemory, etc.) + LOCALE : Locale support API + MISC : what doesn't fit anywhere else. + MUTEX : Mutex management functions + CRITSEC : Critical section API + POLL : ? + CRYPT : Cryptographic functions + SHFOLDER: Shared (well-known) folder functions + SXS : Side-by-side PALs (if supported) + + Note : Most channels correspond to subdirectories $(PALROOT) + Note 2 : DON'T write TRACE("PAL") or TRACE(DCI_PAL), write TRACE(PAL) + +Available debug levels : + ENTRY : use this at the beginning of a function to print parameters. + TRACE : use this to output informational messages. + WARN : use this to report non-critical problems. + ERROR : use this to report critical problems. + + DBGOUT: same as TRACE, but does not output line headers (thread ID, etc) + +Format specifiers : + These trace functions currently use the native fprintf() to output data. + All standard printf format specifiers should therefore work, while Microsoft + extensions will not. + There is one special case to consider : wide strings and wide characters. + Microsoft's extensions to printf include the specifiers %S and %C for + printing strings and characters of wchar_t. In the C99 standard, + the specifiers %ls and %ls serve the same purpose. However, Windows defines + wchar_t as a 16bit int, which is NOT guaranteed to match implementations + on other platforms. glibc on a x86 defines wchar_t as a 32bit int. + For this reason, %S and %C should be used in TRACE functions to output + Windows wide strings (of type wchar_t or WCHAR). To output wide-strings + in a platforms native format (litterals L"string" or variables of type + wchar_native), the specifiers %ls and %lc should be used instead. + +Using Debug channels at Run Time + To tell the PAL which debug channels should be open and which should be + closed, set the environment variable PAL_DBG_CHANNELS according to the + following syntax : + [+|-]<channel>.<level>[: ...] + + opens a channel, - closes it; + <channel> must be one of PAL, FILE, (etc), or the wildcard "all" + <level> must be TRACE, ENTRY, WARN, ERROR or "all" + + Examples (for bash): + + export PAL_DBG_CHANNELS="+PAL.TRACE:-FILE.ERROR" + export PAL_DBG_CHANNELS="+all.ENTRY" + export PAL_DBG_CHANNELS="-all.all" + + To explicitly redirect the output of debug messages to a file (instead of + relying on the shell's > and |), set the environment variable + PAL_API_TRACING to the name of the file to write to. It can also be set to + "stdout" or "stderr". If PAL_API_TRACING is not set, output will go to + stderr. + + ASSERT() messages cannot be controlled with PAL_DBG_CHANNELS; they can be + globally disabled (in debug builds) by setting the environment variable + PAL_DISABLE_ASSERTS to 1. In release builds, they will always be disabled + + The environment variable "PAL_API_LEVELS" determines how many levels of + nesting will be allowed in ENTRY calls; if not set, the default is 1; a + value of 0 will allow infinite nesting, but will not indent the output + + It is possible to disable/enable all channels during the execution of a + process; this involves using a debugger to modify a variable within the + address space of the running process. the variable is named + 'dbg_master_switch'; if set to zero, all debug chanels will be closed; if + set to nonzero, channels will be open or closed based on PAL_DBG_CHANNELS + + Notes : + If _ENABLE_DEBUG_MESSAGES_ was not defined at build-time, no debug messages + will be generated. + If _ENABLE_DEBUG_MESSAGES_ was defined, all debug levels will be enabled, + but all channels will be closed by default + + Another configure option is --enable-appendtraces + Normally, if the file specified by PAL_API_TRACING exists, its content will + be overwritten when a PAL process starts using it. If --enable-appendtraces + is used, debug output will be appended at the end of the file instead. + + + + */ + +#ifndef _PAL_DBGMSG_H_ +#define _PAL_DBGMSG_H_ + +#include "pal/palinternal.h" +#include "config.h" +#include "pal/perftrace.h" +#include "pal/debug.h" +#include "pal/thread.hpp" +#include "pal/tls.hpp" + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/* Channel identifiers */ +typedef enum +{ + DCI_PAL, + DCI_LOADER, + DCI_HANDLE, + DCI_SHMEM, + DCI_PROCESS, + DCI_THREAD, + DCI_EXCEPT, + DCI_CRT, + DCI_UNICODE, + DCI_ARCH, + DCI_SYNC, + DCI_FILE, + DCI_VIRTUAL, + DCI_MEM, + DCI_SOCKET, + DCI_DEBUG, + DCI_LOCALE, + DCI_MISC, + DCI_MUTEX, + DCI_CRITSEC, + DCI_POLL, + DCI_CRYPT, + DCI_SHFOLDER, +#ifdef FEATURE_PAL_SXS + DCI_SXS, +#endif // FEATURE_PAL_SXS + + DCI_LAST +} DBG_CHANNEL_ID; + +/* Level identifiers */ +typedef enum +{ + DLI_ENTRY, + DLI_TRACE, + DLI_WARN, + DLI_ERROR, + DLI_ASSERT, + DLI_EXIT, + + DLI_LAST +} DBG_LEVEL_ID; + + +/* extern variables */ + +// Change W16_NULLSTRING to external variable to avoid multiple warnings showing up in prefast +extern LPCWSTR W16_NULLSTRING; + +extern DWORD dbg_channel_flags[DCI_LAST]; +extern BOOL g_Dbg_asserts_enabled; + +/* we must use stdio functions directly rather that rely on PAL functions for + output, because those functions do tracing and we need to avoid recursion */ +extern FILE *output_file; + +/* master switch for debug channel enablement, to be modified by debugger */ +extern Volatile<BOOL> dbg_master_switch ; + + +/* conditionnal compilation for other debug messages */ +#if !_ENABLE_DEBUG_MESSAGES_ + +/* compile out these trace levels; see the definition of NOTRACE */ +#define TRACE NOTRACE +#define TRACE_(x) NOTRACE +#define WARN NOTRACE +#define WARN_(x) NOTRACE +#define ENTRY_EXTERNAL NOTRACE +#define ENTRY NOTRACE +#define ENTRY_(x) NOTRACE +#define LOGEXIT NOTRACE +#define LOGEXIT_(x) NOTRACE +#define DBGOUT NOTRACE +#define DBGOUT_(x) NOTRACE +#define ERROR NOTRACE +#define ERROR_(x) NOTRACE +#define DBG_PRINTF(level, channel, bHeader) NOTRACE + +#define CHECK_STACK_ALIGN + +#define SET_DEFAULT_DEBUG_CHANNEL(x) +#define DBG_ENABLED(level, channel) + +#else /* _ENABLE_DEBUG_MESSAGES_ */ + +/* output macros */ + +#define SET_DEFAULT_DEBUG_CHANNEL(x) \ + static const DBG_CHANNEL_ID defdbgchan = DCI_##x + +/* Is debug output enabled for the given level and channel? */ +#define DBG_ENABLED(level, channel) (output_file && \ + dbg_master_switch && \ + (dbg_channel_flags[channel] & (1 << (level)))) +#define TRACE \ + DBG_PRINTF(DLI_TRACE,defdbgchan,TRUE) + +#define TRACE_(x) \ + DBG_PRINTF(DLI_TRACE,DCI_##x,TRUE) + +#define WARN \ + DBG_PRINTF(DLI_WARN,defdbgchan,TRUE) + +#define WARN_(x) \ + DBG_PRINTF(DLI_WARN,DCI_##x,TRUE) + +#if _DEBUG && defined(__APPLE__) +bool DBG_ShouldCheckStackAlignment(); +#define CHECK_STACK_ALIGN if (DBG_ShouldCheckStackAlignment()) DBG_CheckStackAlignment() +#else +#define CHECK_STACK_ALIGN +#endif + +#define ENTRY_EXTERNAL \ + CHECK_STACK_ALIGN; \ + DBG_PRINTF(DLI_ENTRY, defdbgchan,TRUE) + +#define ENTRY \ + CHECK_STACK_ALIGN; \ + DBG_PRINTF(DLI_ENTRY, defdbgchan,TRUE) + +#define ENTRY_(x) \ + CHECK_STACK_ALIGN; \ + DBG_PRINTF(DLI_ENTRY, DCI_##x,TRUE) + +#define LOGEXIT \ + DBG_PRINTF(DLI_EXIT, defdbgchan,TRUE) + +#define LOGEXIT_(x) \ + DBG_PRINTF(DLI_EXIT, DCI_##x,TRUE) + +#define DBGOUT \ + DBG_PRINTF(DLI_TRACE,defdbgchan,FALSE) + +#define DBGOUT_(x) \ + DBG_PRINTF(DLI_TRACE,DCI_##x,FALSE) + +/*Added this code here to stop error messages + *from appearing in retail build*/ +#define ERROR \ + DBG_PRINTF(DLI_ERROR,defdbgchan,TRUE) + +#define ERROR_(x) \ + DBG_PRINTF(DLI_ERROR,DCI_##x,TRUE) + +#define DBG_PRINTF(level, channel, bHeader) \ +{\ + if( DBG_ENABLED(level, channel) ) { \ + DBG_CHANNEL_ID __chanid=channel;\ + DBG_LEVEL_ID __levid=level;\ + BOOL __bHeader = bHeader;\ + DBG_PRINTF2 + +#ifdef __GNUC__ +#define DBG_PRINTF2(args...)\ + DBG_printf_gcc(__chanid,__levid,__bHeader,__FUNCTION__,__FILE__,\ + __LINE__,args);\ + }\ +} +#else /* __GNUC__ */ +#define DBG_PRINTF2(...)\ + DBG_printf_c99(__chanid,__levid,__bHeader,__FILE__,__LINE__,__VA_ARGS__);\ + }\ +} +#endif /* __GNUC__ */ + +#endif /* _ENABLE_DEBUG_MESSAGES_ */ + +/* Use GNU C-specific features if available : __FUNCTION__ pseudo-macro, + variable-argument macros */ +#ifdef __GNUC__ + +/* define NOTRACE as nothing; this will absorb the variable-argument list used + in tracing macros */ +#define NOTRACE(args...) + +#if defined(__cplusplus) && defined(FEATURE_PAL_SXS) +#define __ASSERT_ENTER() \ + /* DBG_printf_gcc() and DebugBreak() need a PAL thread */ \ + PAL_EnterHolder __holder(PALIsThreadDataInitialized() && \ + (CorUnix::InternalGetCurrentThread() == NULL || \ + !CorUnix::InternalGetCurrentThread()->IsInPal())); +#else /* __cplusplus && FEATURE_PAL_SXS */ +#define __ASSERT_ENTER() +#endif /* __cplusplus && FEATURE_PAL_SXS */ + +#if !defined(_DEBUG) + +#define ASSERT(args...) +#define _ASSERT(expr) +#define _ASSERTE(expr) +#define _ASSERT_MSG(args...) + +#else /* defined(_DEBUG) */ + +#define ASSERT(args...) \ +{ \ + __ASSERT_ENTER(); \ + if (output_file && dbg_master_switch) \ + { \ + DBG_printf_gcc(defdbgchan,DLI_ASSERT,TRUE,__FUNCTION__,__FILE__,__LINE__,args); \ + } \ + if (g_Dbg_asserts_enabled) \ + { \ + DebugBreak(); \ + } \ +} + +#define _ASSERT(expr) do { if (!(expr)) { ASSERT(""); } } while(0) +#define _ASSERTE(expr) do { if (!(expr)) { ASSERT("Expression: " #expr "\n"); } } while(0) +#define _ASSERT_MSG(expr, args...) \ + do { \ + if (!(expr)) \ + { \ + ASSERT("Expression: " #expr ", Description: " args); \ + } \ + } while(0) + +#endif /* defined(_DEBUG) */ + +#else /* __GNUC__ */ +/* Not GNU C : C99 [the latest version of the ISO C Standard] specifies + a different syntax for variable-argument macros, so try using that*/ +#if defined __STDC_VERSION__ && __STDC_VERSION__ >=199901L + +/* define NOTRACE as nothing; this will absorb the variable-argument list used + in tracing macros */ +#define NOTRACE(...) + +#if !defined(_DEBUG) + +#define ASSERT(...) +#define _ASSERT(expr) +#define _ASSERTE(expr) +#define _ASSERT_MSG(...) + +#else /* defined(_DEBUG) */ + +#define ASSERT(...) \ +{ \ + __ASSERT_ENTER(); \ + if (output_file && dbg_master_switch) \ + { \ + DBG_printf_c99(defdbgchan,DLI_ASSERT,TRUE,__FILE__,__LINE__,__VA_ARGS__); \ + } \ + if(g_Dbg_asserts_enabled) \ + { \ + PAL_Leave(); \ + DebugBreak(); \ + } \ +} + +#define _ASSERT(expr) do { if (!(expr)) { ASSERT(""); } } while(0) +#define _ASSERTE(expr) do { if (!(expr)) { ASSERT("Expression: " #expr "\n"); } } while(0) +#define _ASSERT_MSG(expr, ...) \ + do { \ + if (!(expr)) \ + { \ + ASSERT("Expression: " #expr ", Description: " __VA_ARGS__); \ + } \ + } while(0) + +#endif /* !_DEBUG */ + +#else /* __STDC_VERSION__ */ +/* Not GNU C, not C99 : + possible work around for the lack of variable-argument macros: + by using 2 function calls; must wrap the whole thing in a critical + section to avoid interleaved output from multiple threads */ + +#error The compiler is missing support for variable-argument macros. + +#endif /* __STDC_VERSION__*/ +#endif /* __GNUC__ */ + +/* Function declarations */ + +/*++ +Function : + DBG_init_channels + + Initialize debug channel information based on environment settings + Call this only once at startup. + + (no parameters, no return value) +--*/ +BOOL DBG_init_channels(void); + +/*++ +Function : + DBG_close_channels + + Close the output file for debug messages. + + (no parameters, no return value) +--*/ +void DBG_close_channels(void); + +/*++ +Function : + DBG_preprintf + + Internal function for debug channels; don't use. + This function outputs the header information for debug messages (channel, + level, etc). + +Parameters : + DBG_CHANNEL_ID channel : debug channel to use + DBG_LEVEL_ID level : debug message level + BOOL bHeader : whether or not to output message header (thread id, etc) + LPSTR file : current file + INT line : line number + +Return Value : + TRUE if there's an output file, FALSE otherwise. this is so that + DBG_printf_plain doesn't get called unnecessarily. + +Notes : + This function is only used with compilers that don't support + variable-argument macros. It enters a critical section, which is left in + DBG_printf_plain. +--*/ +BOOL DBG_preprintf(DBG_CHANNEL_ID channel, DBG_LEVEL_ID level, BOOL bHeader, + LPSTR file, INT line); + +/*++ +Function : + DBG_printf_gcc + + Internal function for debug channels; don't use. + This function outputs a complete debug message, including the function name. + +Parameters : + DBG_CHANNEL_ID channel : debug channel to use + DBG_LEVEL_ID level : debug message level + BOOL bHeader : whether or not to output message header (thread id, etc) + LPSTR function : current function + LPSTR file : current file + INT line : line number + LPSTR format, ... : standard printf parameter list. + +Return Value : + always 1. + +Notes : + This version is for gnu compilers that support variable-argument macros + and the __FUNCTION__ pseudo-macro. + +--*/ +#if __GNUC__ && CHECK_TRACE_SPECIFIERS +/* if requested, use an __attribute__ feature to ask gcc to check that format + specifiers match their parameters */ +int DBG_printf_gcc(DBG_CHANNEL_ID channel, DBG_LEVEL_ID level, BOOL bHeader, + LPCSTR function, LPCSTR file, INT line, LPCSTR format, ...) + __attribute__ ((format (printf,7, 8))); +#else +int DBG_printf_gcc(DBG_CHANNEL_ID channel, DBG_LEVEL_ID level, BOOL bHeader, + LPCSTR function, LPCSTR file, INT line, LPCSTR format, ...); +#endif + +/*++ +Function : + DBG_printf_c99 + + Internal function for debug channels; don't use. + This function outputs a complete debug message, without function name. + +Parameters : + DBG_CHANNEL_ID channel : debug channel to use + DBG_LEVEL_ID level : debug message level + BOOL bHeader : whether or not to output message header (thread id, etc) + LPSTR file : current file + INT line : line number + LPSTR format, ... : standard printf parameter list. + +Return Value : + always 1. + +Notes : + This version is for compilers that support the C99 flavor of + variable-argument macros but not the gnu flavor, and do not support the + __FUNCTION__ pseudo-macro. + +--*/ +int DBG_printf_c99(DBG_CHANNEL_ID channel, DBG_LEVEL_ID level, BOOL bHeader, + LPSTR file, INT line, LPSTR format, ...); + +/*++ +Function : + DBG_printf_plain + + Internal function for debug channels; don't use. + This function output the user-specified part of a debug-message. + +Parameters : + LPSTR format, ... : standard printf parameter list. + +Return value : + always 1. + +Notes : + This function is only used with compilers that don't support + variable-argument macros. It will leave the critical section entered in + DBG_preprintf. + +--*/ +int DBG_printf_plain(LPSTR format, ...); + +/*++ +Function : + DBG_change_entrylevel + + retrieve current ENTRY nesting level and [optionnally] modify it + +Parameters : + int new_level : value to which the nesting level must be set, or -1 + +Return value : + nesting level at the time the function was called + +Notes: +if new_level is -1, the nesting level will not be modified +--*/ +int DBG_change_entrylevel(int new_level); + +#ifdef __APPLE__ +/*++ +Function : + PAL_DisplayDialog + + Display a simple modal dialog with an alert icon and a single OK button. Caller supplies the title of the + dialog and the main text. The dialog is displayed only if the COMPlus_EnableAssertDialog environment + variable is set to the value "1". + +--*/ +void PAL_DisplayDialog(const char *szTitle, const char *szText); + +/*++ +Function : + PAL_DisplayDialogFormatted + + As above but takes a printf-style format string and insertion values to form the main text. + +--*/ +void PAL_DisplayDialogFormatted(const char *szTitle, const char *szTextFormat, ...); +#else // __APPLE__ +#define PAL_DisplayDialog(_szTitle, _szText) +#define PAL_DisplayDialogFormatted(_szTitle, _szTextFormat, args...) +#endif // __APPLE__ + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* _PAL_DBGMSG_H_ */ + + diff --git a/src/pal/src/include/pal/debug.h b/src/pal/src/include/pal/debug.h new file mode 100644 index 0000000000..78cdeff0c3 --- /dev/null +++ b/src/pal/src/include/pal/debug.h @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/debug.h + +Abstract: + + Debug API utility functions + + + +--*/ + +#ifndef _PAL_DEBUG_H_ +#define _PAL_DEBUG_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/*++ +Function : + DBG_DebugBreak + + Processor-dependent implementation of DebugBreak + +(no parameters, no return value) +--*/ +extern "C" VOID +DBG_DebugBreak(); + +/*++ +Function: + IsInDebugBreak(addr) + + Returns true if the address is in DBG_DebugBreak. + +--*/ +BOOL +IsInDebugBreak(void *addr); + +/*++ +Function : + DBG_FlushInstructionCache + + Processor-dependent implementation of FlushInstructionCache + +Parameters : + LPCVOID lpBaseAddress: start of region to flush + SIZE_T dwSize : length of region to flush + +Return value : + TRUE on success, FALSE on failure + +--*/ +BOOL +DBG_FlushInstructionCache( + IN LPCVOID lpBaseAddress, + IN SIZE_T dwSize); + +#if defined(__APPLE__) +/*++ +Function: + DBG_CheckStackAlignment + + The Apple ABI requires 16-byte alignment on the stack pointer. + This function traps/interrupts otherwise. +--*/ +VOID +DBG_CheckStackAlignment(); +#endif + + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif //PAL_DEBUG_H_ diff --git a/src/pal/src/include/pal/dtraceprotocol.h b/src/pal/src/include/pal/dtraceprotocol.h new file mode 100644 index 0000000000..d1a17a71ae --- /dev/null +++ b/src/pal/src/include/pal/dtraceprotocol.h @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// +// File: rotor/pal/corunix/include/pal/dtrace_protocal.h +// + +// +// Header file for the protocals between CLR and Dtrace server +// +// ====================================================================================== + +#ifndef DTRACE_PROTOCOL_H +#define DTRACE_PROTOCOL_H + +// Start DTrace Consumer by Unix Domain App +#define kServerSocketPath "/Library/Application Support/com.microsoft.clr.CFDtraceServer/Socket" +#define kPacketTypeStartDtrace 1 +#define kPacketTypeReply 3 +#define kMaxMessageSize 318 +#define kPacketMaximumSize 102400 + +struct PacketHeader { + int fType; // for request from client to server, it should be kPacketTypeStartDtrace + // for reply from server to client, it should be kPacketTypeReply + unsigned int fSize; // includes size of header itself +}; + +struct PacketStartDTrace { // reply: PacketReply + PacketHeader fHeader; // fType is kPacketTypeStartDtrace + char fMessage[kMaxMessageSize]; // message to print +}; + +struct PacketReply { // reply: n/a + PacketHeader fHeader; // fType is kPacketTypeReply + int fErr; // result of operation, errno-style +}; + +#endif // DTRACE_PROTOCOL diff --git a/src/pal/src/include/pal/environ.h b/src/pal/src/include/pal/environ.h new file mode 100644 index 0000000000..1c0bce21ca --- /dev/null +++ b/src/pal/src/include/pal/environ.h @@ -0,0 +1,78 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/environ.h + +Abstract: + Header file for functions manipulating environment variables + + +--*/ + +#ifndef __ENVIRON_H_ +#define __ENVIRON_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/*++ +Variables : + + palEnvironment: a global variable equivalent to environ on systems on + which that exists, and a pointer to an array of environment + strings on systems without environ. + gcsEnvironment: critical section to synchronize access to palEnvironment +--*/ +extern char **palEnvironment; +extern CRITICAL_SECTION gcsEnvironment; + +/*++ + +Function: + EnvironInitialize + +Initialization function for the PAL environment code. +--*/ +BOOL EnvironInitialize(); + +/*++ +Function: + EnvironGetenv + +Get the value of environment variable with the given name. +--*/ +char *EnvironGetenv(const char *name, BOOL copyValue = TRUE); + +/*++ +Function: + EnvironPutenv + +Add the environment variable string provided to the PAL version +of the environment. +--*/ +BOOL EnvironPutenv(const char *string, BOOL deleteIfEmpty); + +/*++ +Function: + EnvironUnsetenv + +Remove the environment variable with the given name from the PAL +version of the environment if it exists. +--*/ +void EnvironUnsetenv(const char *name); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* __ENVIRON_H_ */ + diff --git a/src/pal/src/include/pal/event.hpp b/src/pal/src/include/pal/event.hpp new file mode 100644 index 0000000000..98eeaee5db --- /dev/null +++ b/src/pal/src/include/pal/event.hpp @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + event.hpp + +Abstract: + + Event object structure definition. + + + +--*/ + +#ifndef _PAL_EVENT_H_ +#define _PAL_EVENT_H_ + +#include "corunix.hpp" + +namespace CorUnix +{ + extern CObjectType otManualResetEvent; + extern CObjectType otAutoResetEvent; + + PAL_ERROR + InternalCreateEvent( + CPalThread *pThread, + LPSECURITY_ATTRIBUTES lpEventAttributes, + BOOL bManualReset, + BOOL bInitialState, + LPCWSTR lpName, + HANDLE *phEvent + ); + + PAL_ERROR + InternalSetEvent( + CPalThread *pThread, + HANDLE hEvent, + BOOL fSetEvent + ); + + PAL_ERROR + InternalOpenEvent( + CPalThread *pThread, + DWORD dwDesiredAccess, + BOOL bInheritHandle, + LPCWSTR lpName, + HANDLE *phEvent + ); + +} + +#endif //PAL_EVENT_H_ + + + + + + + + + + diff --git a/src/pal/src/include/pal/fakepoll.h b/src/pal/src/include/pal/fakepoll.h new file mode 100644 index 0000000000..eec40d6612 --- /dev/null +++ b/src/pal/src/include/pal/fakepoll.h @@ -0,0 +1,68 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// fakepoll.h +// poll using select +// Warning: a call to this poll() takes about 4K of stack space. + +// Greg Parker gparker@cs.stanford.edu December 2000 +// This code is in the public domain and may be copied or modified without +// permission. + +// Located at <http://www.sealiesoftware.com/fakepoll.h>. + + + + +#ifndef _FAKE_POLL_H +#define _FAKE_POLL_H + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +#ifdef FD_SETSIZE +#undef FD_SETSIZE +#endif +#define FD_SETSIZE OPEN_MAX + +typedef struct pollfd { + int fd; /* file desc to poll */ + short events; /* events of interest on fd */ + short revents; /* events that occurred on fd */ +} pollfd_t; + +// Typically defined in sys/stropts.h and used for an infinite timeout. +#ifndef _INFTIM +#define _INFTIM -1 +#endif +#ifndef INFTIM +#define INFTIM _INFTIM +#endif + +// poll flags +#define POLLIN 0x0001 +#define POLLOUT 0x0004 +#define POLLERR 0x0008 + +// synonyms +#define POLLNORM POLLIN +#define POLLPRI POLLIN +#define POLLRDNORM POLLIN +#define POLLRDBAND POLLIN +#define POLLWRNORM POLLOUT +#define POLLWRBAND POLLOUT + +// ignored +#define POLLHUP 0x0010 +#define POLLNVAL 0x0020 + +int poll(struct pollfd *pollSet, int pollCount, int pollTimeout); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* _FAKE_POLL_H */ diff --git a/src/pal/src/include/pal/file.h b/src/pal/src/include/pal/file.h new file mode 100644 index 0000000000..93c8ad9784 --- /dev/null +++ b/src/pal/src/include/pal/file.h @@ -0,0 +1,304 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/file.h + +Abstract: + Header file for file utility functions. + +Revision History: + + + +--*/ + +#ifndef _PAL_FILE_H_ +#define _PAL_FILE_H_ + +#include "pal/shmemory.h" +#include "pal/stackstring.hpp" +#include <sys/types.h> +#include <dirent.h> + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +typedef struct _find_handle +{ + struct _find_handle *self_addr; /* for pointer verification */ + + char dir[_MAX_DIR]; + char fname[MAX_PATH_FNAME]; /* includes extension */ + glob_t gGlob; + char **next; +} find_obj; + +/*++ +FILECanonicalizePath + Removes all instances of '/./', '/../' and '//' from an absolute path. + +Parameters: + LPSTR lpUnixPath : absolute path to modify, in Unix format + +(no return value) + +Notes : +-behavior is undefined if path is not absolute +-the order of steps *is* important: /one/./../two would give /one/two + instead of /two if step 3 was done before step 2 +-reason for this function is that GetFullPathName can't use realpath(), since + realpath() requires the given path to be valid and GetFullPathName does not. +--*/ +void FILECanonicalizePath(LPSTR lpUnixPath); + +/*++ +Function: + FileDosToUnixPathA + +Abstract: + Change a DOS path to a Unix path. Replace '\' by '/'. + +Parameter: + IN/OUT lpPath: path to be modified +--*/ +void +FILEDosToUnixPathA(LPSTR lpPath); + +/*++ +Function: + FileDosToUnixPathW + +Abstract: + Change a DOS path to a Unix path. Replace '\' by '/'. + +Parameter: + IN/OUT lpPath: path to be modified + --*/ +void +FILEDosToUnixPathW(LPWSTR lpPath); + +/*++ +Function: + FileUnixToDosPathA + +Abstract: + Change a Unix path to a DOS path. Replace '/' by '\'. + +Parameter: + IN/OUT lpPath: path to be modified +--*/ +void +FILEUnixToDosPathA(LPSTR lpPath); + +/*++ +Function: + FILEGetDirectoryFromFullPathA + +Parse the given path. If it contains a directory part and a file part, +put the directory part into the supplied buffer, and return the number of +characters written to the buffer. If the buffer is not large enough, +return the required size of the buffer including the NULL character. If +there is no directory part in the path, return 0. +--*/ +DWORD FILEGetDirectoryFromFullPathA( LPCSTR lpFullPath, + DWORD nBufferLength, + LPSTR lpBuffer ); + +/*++ +Function: + FILEGetFileNameFromFullPath + +Given a full path, return a pointer to the first char of the filename part. +--*/ +LPCSTR FILEGetFileNameFromFullPathA( LPCSTR lpFullPath ); + +/*++ +Function: + FILEGetLastErrorFromErrno + +Convert errno into the appropriate win32 error and return it. +--*/ +DWORD FILEGetLastErrorFromErrno( void ); + +/*++ +Function: + DIRGetLastErrorFromErrno + +Convert errno into the appropriate win32 error and return it. +--*/ +DWORD DIRGetLastErrorFromErrno( void ); + +/*++ +FILEInitStdHandles + +Create handle objects for stdin, stdout and stderr + +(no parameters) + +Return value: + TRUE on success, FALSE on failure +--*/ +BOOL FILEInitStdHandles(void); + +/*++ +FILECleanupStdHandles + +Close promary handles for stdin, stdout and stderr + +(no parameters, no return value) +--*/ +void FILECleanupStdHandles(void); + +/*++ + +Function : + FILEGetProperNotFoundError + +Returns the proper error code, based on the +Windows behavoir. + + IN LPSTR lpPath - The path to check. + LPDWORD lpErrorCode - The error to set. +*/ +void FILEGetProperNotFoundError( LPCSTR lpPath, LPDWORD lpErrorCode ); + +/*++ +PAL__getcwd + +Calls getcwd + +Input parameters: + +char *szBuf = a copy of the absolute pathname of the current working directory +is copied into szBuf. +size_t nSize = size, in bytes, of the array referenced by szBuf. + +Return value: + A pointer to the pathname if successful, otherwise NULL is returned. +--*/ +char * __cdecl PAL__getcwd(char *szBuf, size_t nSize); + +/*++ +PAL_fflush + +Calls fflush + +Input parameters: + +PAL_FILE *stream = stream to be flushed. + +Return value: + 0 is returned on success, otherwise EOF is returned. +--*/ +int _cdecl PAL_fflush( PAL_FILE *stream ); + +/*++ +PAL_mkstemp + +Calls InternalMkstemp to call mkstemp + +Input parameters: + +char *szNameTemplate = the pattern to follow when creating a new file. + +Return value: + file descriptor of opened file on success, -1 on failure. +--*/ +int __cdecl PAL_mkstemp(char *szNameTemplate); + +/*++ +PAL_rename + +Calls rename + +Input parameters: + +szOldName = pointer to the pathname of the file to be renamed +szNewName = pointer to the new pathname of the file + +Return value: + Returns 0 on success and -1 on failure +--*/ +int __cdecl PAL_rename(const char *szOldName, const char *szNewName); + +/*++ +PAL_fgets + +Wrapper function for InternalFgets. + +Input parameters: + +sz = stores characters read from the given file stream +nSize = number of characters to be read +pf = stream to read characters from + +Return value: + Returns a pointer to the string storing the characters on success + and NULL on failure. +--*/ +char * __cdecl PAL_fgets(char *sz, int nSize, PAL_FILE *pf); + +/*++ +PAL_fwrite + +Wrapper function for InternalFwrite + +Input parameters: + +pvBuffer = array of objects to write to the given file stream +nSize = size of a object in bytes +nCount = number of objects to write +pf = stream to write characters to + +Return value: + Returns the number of objects written. +--*/ +size_t __cdecl PAL_fwrite(const void *pvBuffer, size_t nSize, size_t nCount, PAL_FILE *pf); + +/*++ +PAL__open + +Wrapper function for InternalOpen. + +Input parameters: + +szPath = pointer to a pathname of a file to be opened +nFlags = arguments that control how the file should be accessed +mode = file permission settings that are used only when a file is created + +Return value: + File descriptor on success, -1 on failure +--*/ +int __cdecl PAL__open(const char *szPath, int nFlags, ...); + +/*++ +PAL_fseek + +Wrapper function for fseek + +Input parameters: + +pf = a given file stream +lOffset = distance from position to set file-position indicator +nWhence = method used to determine the file_position indicator location relative to lOffset + +Return value: + 0 on success, -1 on failure. +--*/ +int _cdecl PAL_fseek(PAL_FILE *pf, LONG lOffset, int nWhence); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* _PAL_FILE_H_ */ + diff --git a/src/pal/src/include/pal/file.hpp b/src/pal/src/include/pal/file.hpp new file mode 100644 index 0000000000..5acccb0a24 --- /dev/null +++ b/src/pal/src/include/pal/file.hpp @@ -0,0 +1,365 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/file.hpp + +Abstract: + Header file for file utility functions. + +Revision History: + + + +--*/ + +#ifndef _PAL_FILE_HPP_ +#define _PAL_FILE_HPP_ + +#include "corunix.hpp" +#include "pal/stackstring.hpp" +#include <sys/types.h> +#include <sys/param.h> +#include <dirent.h> + + +namespace CorUnix +{ + extern CObjectType otFile; + extern CAllowedObjectTypes aotFile; + + class CFileProcessLocalData + { + public: + IFileLockController *pLockController; + + int unix_fd; + DWORD dwDesiredAccess; /* Unix assumes files are always opened for reading. + In Windows we can open a file for writing only */ + int open_flags; /* stores Unix file creation flags */ + BOOL open_flags_deviceaccessonly; + char unix_filename[MAXPATHLEN]; + BOOL inheritable; + }; + + PAL_ERROR + InternalCreateFile( + CPalThread *pThread, + LPCSTR lpFileName, + DWORD dwDesiredAccess, + DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, + HANDLE hTemplateFile, + HANDLE *pFileHandle + ); + + PAL_ERROR + InternalWriteFile( + CPalThread *pThread, + HANDLE hFile, + LPCVOID lpBuffer, + DWORD nNumberOfBytesToWrite, + LPDWORD lpNumberOfBytesWritten, + LPOVERLAPPED lpOverlapped + ); + + PAL_ERROR + InternalReadFile( + CPalThread *pThread, + HANDLE hFile, + LPVOID lpBuffer, + DWORD nNumberOfBytesToRead, + LPDWORD lpNumberOfBytesRead, + LPOVERLAPPED lpOverlapped + ); + + PAL_ERROR + InternalSetEndOfFile( + CPalThread *pThread, + HANDLE hFile + ); + + PAL_ERROR + InternalGetFileSize( + CPalThread *pThread, + HANDLE hFile, + DWORD *pdwFileSizeLow, + DWORD *pdwFileSizeHigh + ); + + PAL_ERROR + InternalFlushFileBuffers( + CPalThread *pThread, + HANDLE hFile + ); + + PAL_ERROR + InternalGetFileType( + CPalThread *pThread, + HANDLE hFile, + DWORD *pdwFileType + ); + + PAL_ERROR + InternalCreatePipe( + CPalThread *pThread, + HANDLE *phReadPipe, + HANDLE *phWritePipe, + LPSECURITY_ATTRIBUTES lpPipeAttributes, + DWORD nSize + ); + + PAL_ERROR + InternalLockFile( + CPalThread *pThread, + HANDLE hFile, + DWORD dwFileOffsetLow, + DWORD dwFileOffsetHigh, + DWORD nNumberOfBytesToLockLow, + DWORD nNumberOfBytesToLockHigh + ); + + PAL_ERROR + InternalUnlockFile( + CPalThread *pThread, + HANDLE hFile, + DWORD dwFileOffsetLow, + DWORD dwFileOffsetHigh, + DWORD nNumberOfBytesToUnlockLow, + DWORD nNumberOfBytesToUnlockHigh + ); + + PAL_ERROR + InternalSetFilePointer( + CPalThread *pThread, + HANDLE hFile, + LONG lDistanceToMove, + PLONG lpDistanceToMoveHigh, + DWORD dwMoveMethod, + PLONG lpNewFilePointerLow + ); + + PAL_ERROR + InternalSetFileTime( + CPalThread *pThread, + IN HANDLE hFile, + IN CONST FILETIME *lpCreationTime, + IN CONST FILETIME *lpLastAccessTime, + IN CONST FILETIME *lpLastWriteTime + ); + + PAL_ERROR + InternalGetFileTime( + CPalThread *pThread, + IN HANDLE hFile, + OUT LPFILETIME lpCreationTime, + OUT LPFILETIME lpLastAccessTime, + OUT LPFILETIME lpLastWriteTime + ); + + BOOL + RealPathHelper(LPCSTR lpUnixPath, PathCharString& lpBuffer); + /*++ + InternalCanonicalizeRealPath + Wraps realpath() to hide platform differences. See the man page for + realpath(3) for details of how realpath() works. + + On systems on which realpath() allows the last path component to not + exist, this is a straight thunk through to realpath(). On other + systems, we remove the last path component, then call realpath(). + --*/ + PAL_ERROR + InternalCanonicalizeRealPath( + LPCSTR lpUnixPath, + PathCharString& lpBuffer + ); + + /*++ + InternalMkstemp + Wraps mkstemp + --*/ + int + InternalMkstemp( + char *szNameTemplate + ); + + /*++ + InternalFgets + Wraps fgets + --*/ + char * + InternalFgets( + char *sz, + int nSize, + FILE *f, + bool fTextMode + ); + + /*++ + InternalFwrite + Wraps fwrite + --*/ + size_t + InternalFwrite( + const void *pvBuffer, + size_t nSize, + size_t nCount, + FILE *f, + INT *pnErrorCode + ); + + /*++ + InternalOpen + Wraps open + --*/ + int + InternalOpen( + const char *szFilename, + int nFlags, + ... + ); +} + +extern "C" +{ + +// +// These routines should all be separated out into something along the lines +// of fileutils.* (instead of being commingled with the core file object +// code). +// + +/*++ +FILECanonicalizePath + Removes all instances of '/./', '/../' and '//' from an absolute path. + +Parameters: + LPSTR lpUnixPath : absolute path to modify, in Unix format + +(no return value) + +Notes : +-behavior is undefined if path is not absolute +-the order of steps *is* important: /one/./../two would give /one/two + instead of /two if step 3 was done before step 2 +-reason for this function is that GetFullPathName can't use realpath(), since + realpath() requires the given path to be valid and GetFullPathName does not. +--*/ +void FILECanonicalizePath(LPSTR lpUnixPath); + +/*++ +Function: + FileDosToUnixPathA + +Abstract: + Change a DOS path to a Unix path. Replace '\' by '/'. + +Parameter: + IN/OUT lpPath: path to be modified +--*/ +void +FILEDosToUnixPathA(LPSTR lpPath); + +/*++ +Function: + FileDosToUnixPathW + +Abstract: + Change a DOS path to a Unix path. Replace '\' by '/'. + +Parameter: + IN/OUT lpPath: path to be modified + --*/ +void +FILEDosToUnixPathW(LPWSTR lpPath); + +/*++ +Function: + FileUnixToDosPathA + +Abstract: + Change a Unix path to a DOS path. Replace '/' by '\'. + +Parameter: + IN/OUT lpPath: path to be modified +--*/ +void +FILEUnixToDosPathA(LPSTR lpPath); + + +/*++ +Function: + FILEGetDirectoryFromFullPathA + +Parse the given path. If it contains a directory part and a file part, +put the directory part into the supplied buffer, and return the number of +characters written to the buffer. If the buffer is not large enough, +return the required size of the buffer including the NULL character. If +there is no directory part in the path, return 0. +--*/ +DWORD FILEGetDirectoryFromFullPathA( LPCSTR lpFullPath, + DWORD nBufferLength, + LPSTR lpBuffer ); + +/*++ +Function: + FILEGetFileNameFromFullPath + +Given a full path, return a pointer to the first char of the filename part. +--*/ +LPCSTR FILEGetFileNameFromFullPathA( LPCSTR lpFullPath ); + +/*++ +Function: + FILEGetLastErrorFromErrno + +Convert errno into the appropriate win32 error and return it. +--*/ +DWORD FILEGetLastErrorFromErrno( void ); + +/*++ +FILEInitStdHandles + +Create handle objects for stdin, stdout and stderr + +(no parameters) + +Return value: + TRUE on success, FALSE on failure +--*/ +BOOL FILEInitStdHandles(void); + +/*++ +FILECleanupStdHandles + +Close primary handles for stdin, stdout and stderr + +(no parameters, no return value) +--*/ +void FILECleanupStdHandles(void); + +/*++ + +Function : + FILEGetProperNotFoundError + +Returns the proper error code, based on the +Windows behavoir. + + IN LPSTR lpPath - The path to check. + LPDWORD lpErrorCode - The error to set. +*/ +void FILEGetProperNotFoundError( LPCSTR lpPath, LPDWORD lpErrorCode ); + +} + +#endif /* _PAL_FILE_HPP_ */ + diff --git a/src/pal/src/include/pal/filetime.h b/src/pal/src/include/pal/filetime.h new file mode 100644 index 0000000000..cb37b4115a --- /dev/null +++ b/src/pal/src/include/pal/filetime.h @@ -0,0 +1,80 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/filetime.h + +Abstract: + + Header file for utility functions having to do with file times. + +Revision History: + + + +--*/ + +#ifndef _PAL_FILETIME_H_ +#define _PAL_FILETIME_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/* Provide consistent access to nanosecond fields, if they exist. */ + +#if HAVE_STAT_TIMESPEC + +#define ST_ATIME_NSEC(statstruct) ((statstruct)->st_atimespec.tv_nsec) +#define ST_MTIME_NSEC(statstruct) ((statstruct)->st_mtimespec.tv_nsec) +#define ST_CTIME_NSEC(statstruct) ((statstruct)->st_ctimespec.tv_nsec) + +#else /* HAVE_STAT_TIMESPEC */ + +#if HAVE_STAT_NSEC + +#define ST_ATIME_NSEC(statstruct) ((statstruct)->st_atimensec) +#define ST_MTIME_NSEC(statstruct) ((statstruct)->st_mtimensec) +#define ST_CTIME_NSEC(statstruct) ((statstruct)->st_ctimensec) + +#else /* HAVE_STAT_NSEC */ + +#define ST_ATIME_NSEC(statstruct) 0 +#define ST_MTIME_NSEC(statstruct) 0 +#define ST_CTIME_NSEC(statstruct) 0 + +#endif /* HAVE_STAT_NSEC */ +#endif /* HAVE_STAT_TIMESPEC */ + +FILETIME FILEUnixTimeToFileTime( time_t sec, long nsec ); +time_t FILEFileTimeToUnixTime( FILETIME FileTime, long *nsec ); + +#ifdef __APPLE__ +#include <CoreFoundation/CFDate.h> + +FILETIME FILECFAbsoluteTimeToFileTime( CFAbsoluteTime sec ); +#endif // __APPLE__ + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* _PAL_FILE_H_ */ + + + + + + + + + + + diff --git a/src/pal/src/include/pal/handleapi.hpp b/src/pal/src/include/pal/handleapi.hpp new file mode 100644 index 0000000000..7974432a65 --- /dev/null +++ b/src/pal/src/include/pal/handleapi.hpp @@ -0,0 +1,48 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + handleapi.hpp + +Abstract: + + Declaration of the handle management APIs + + + +--*/ + +#ifndef _HANDLEAPI_HPP +#define _HANDLEAPI_HPP + +#include "corunix.hpp" + +namespace CorUnix +{ + PAL_ERROR + InternalDuplicateHandle( + CPalThread *pThread, + HANDLE hSourceProcess, + HANDLE hSource, + HANDLE hTargetProcess, + LPHANDLE phDuplicate, + DWORD dwDesiredAccess, + BOOL bInheritHandle, + DWORD dwOptions + ); + + PAL_ERROR + InternalCloseHandle( + CPalThread *pThread, + HANDLE hObject + ); +} + +#endif // _HANDLEAPI_HPP + diff --git a/src/pal/src/include/pal/handlemgr.hpp b/src/pal/src/include/pal/handlemgr.hpp new file mode 100644 index 0000000000..1fbdb87199 --- /dev/null +++ b/src/pal/src/include/pal/handlemgr.hpp @@ -0,0 +1,180 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + handlemgr.hpp + +Abstract: + + Simple handle table manager class + + + +--*/ + +#ifndef _PAL_HANDLEMGR_H_ +#define _PAL_HANDLEMGR_H_ + + +#include "corunix.hpp" +#include "cs.hpp" +#include "pal/thread.hpp" +#include "pal/malloc.hpp" + + +/* Pseudo handles constant for current thread and process */ +extern const HANDLE hPseudoCurrentProcess; +extern const HANDLE hPseudoCurrentThread; +extern const HANDLE hPseudoGlobalIOCP; + +namespace CorUnix +{ + class CSimpleHandleManager + { + private: + enum { c_BasicGrowthRate = 1024 }; + enum { c_MaxIndex = 0x3FFFFFFE }; + + typedef UINT_PTR HANDLE_INDEX; + static const HANDLE_INDEX c_hiInvalid = (HANDLE_INDEX) -1; + + HANDLE + HandleIndexToHandle(HANDLE_INDEX hi) + { + return (HANDLE) ((hi + 1) << 2); + }; + + HANDLE_INDEX + HandleToHandleIndex(HANDLE h) + { + return (HANDLE_INDEX) (((UINT_PTR) h) >> 2) - 1; + }; + + typedef struct _HANDLE_TABLE_ENTRY + { + union + { + IPalObject *pObject; + HANDLE_INDEX hiNextIndex; + } u; + + DWORD dwAccessRights; + bool fInheritable; + + bool fEntryAllocated; + } HANDLE_TABLE_ENTRY; + + HANDLE_INDEX m_hiFreeListStart; + HANDLE_INDEX m_hiFreeListEnd; + + DWORD m_dwTableSize; + DWORD m_dwTableGrowthRate; + HANDLE_TABLE_ENTRY* m_rghteHandleTable; + + CRITICAL_SECTION m_csLock; + bool m_fLockInitialized; + + bool ValidateHandle(HANDLE h); + + public: + + CSimpleHandleManager() + : + m_hiFreeListStart(c_hiInvalid), + m_hiFreeListEnd(c_hiInvalid), + m_dwTableSize(0), + m_dwTableGrowthRate(c_BasicGrowthRate), + m_rghteHandleTable(NULL), + m_fLockInitialized(FALSE) + { + }; + + virtual + ~CSimpleHandleManager() + { + if (m_fLockInitialized) + { + DeleteCriticalSection(&m_csLock); + } + + if (NULL != m_rghteHandleTable) + { + free(m_rghteHandleTable); + } + } + + PAL_ERROR + Initialize( + void + ); + + PAL_ERROR + AllocateHandle( + CPalThread *pThread, + IPalObject *pObject, + DWORD dwAccessRights, + bool fInheritable, + HANDLE *ph + ); + + // + // On success this will add a reference to the returned object. + // + + PAL_ERROR + GetObjectFromHandle( + CPalThread *pThread, + HANDLE h, + DWORD *pdwRightsGranted, + IPalObject **ppObject + ); + + PAL_ERROR + FreeHandle( + CPalThread *pThread, + HANDLE h + ); + + void + Lock( + CPalThread *pThread + ) + { + InternalEnterCriticalSection(pThread, &m_csLock); + }; + + void + Unlock( + CPalThread *pThread + ) + { + InternalLeaveCriticalSection(pThread, &m_csLock); + }; + }; + + bool + HandleIsSpecial( + HANDLE h + ); +} + +#endif // _PAL_HANDLEMGR_H_ + + + + + + + + + + + + + diff --git a/src/pal/src/include/pal/identity.hpp b/src/pal/src/include/pal/identity.hpp new file mode 100644 index 0000000000..bd64a659ac --- /dev/null +++ b/src/pal/src/include/pal/identity.hpp @@ -0,0 +1,57 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/identity.hpp + +Abstract: + + Header file for identity functions. + + + +--*/ + +#ifndef _PAL_IDENTITY_HPP_ +#define _PAL_IDENTITY_HPP_ + +#include "config.h" +#include "pal/palinternal.h" + +/*++ + +Function: + IdentityInitialize + +--*/ +BOOL IdentityInitialize(); + +/*++ +Function: + IdentityCleanup + +--*/ +VOID IdentityCleanup(); + +#if HAVE_GETPWUID_R +namespace CorUnix +{ + int + InternalGetpwuid_r( + CPalThread *pPalThread, + uid_t uid, + struct passwd *pPasswd, + char *pchBuffer, + size_t nBufSize, + struct passwd **ppResult + ); +} +#endif /* HAVE_GETPWUID_R */ + +#endif /* _PAL_IDENTITY_HPP_ */ diff --git a/src/pal/src/include/pal/init.h b/src/pal/src/include/pal/init.h new file mode 100644 index 0000000000..d478ed275b --- /dev/null +++ b/src/pal/src/include/pal/init.h @@ -0,0 +1,111 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/init.h + +Abstract: + Header file for PAL init utility functions. Those functions + are only use by the PAL itself. + +Revision History: + + + +--*/ + +#ifndef _PAL_INIT_H_ +#define _PAL_INIT_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/*++ +Function: + PALCommonCleanup + +Utility function to prepare for shutdown. + +--*/ +void PALCommonCleanup(); + +extern Volatile<INT> init_count; + +/*++ +MACRO: + PALIsInitialized + +Returns TRUE if the PAL is in an initialized state +(#calls to PAL_Initialize > #calls to PAL_Terminate) + +Warning : this will only report the PAL's state at the moment it is called. +If it is necessary to ensure the PAL remains initialized (or not) while doing +some work, the Initialization lock (PALInitLock()) should be held. +--*/ +#define PALIsInitialized() (0 < init_count) + +/*++ +Function: + PALIsThreadDataInitialized + +Returns TRUE if startup has reached a point where thread data is available +--*/ +BOOL +PALIsThreadDataInitialized(); + +/*++ +Function: + PALIsShuttingDown + +Returns TRUE if the some thread has declared intent to shutdown +--*/ +BOOL +PALIsShuttingDown(); + +/*++ +Function: + PALSetShutdownIntent + +Delcares intent to shutdown +--*/ +void +PALSetShutdownIntent(); + +/*++ +Function: + PALInitLock + +Take the initializaiton critical section (init_critsec). necessary to serialize +TerminateProcess along with PAL_Terminate and PAL_Initialize + +(no parameters) + +Return value : + TRUE if critical section existed (and was acquired) + FALSE if critical section doens't exist yet +--*/ +BOOL PALInitLock(void); + +/*++ +Function: + PALInitUnlock + +Release the initialization critical section (init_critsec). + +(no parameters, no return value) +--*/ +void PALInitUnlock(void); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* _PAL_INIT_H_ */ diff --git a/src/pal/src/include/pal/list.h b/src/pal/src/include/pal/list.h new file mode 100644 index 0000000000..cd78c0f03a --- /dev/null +++ b/src/pal/src/include/pal/list.h @@ -0,0 +1,141 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + list.h + +Abstract: + + Doubly-linked list manipulation macros (from ntrtl.h) + +Revision History: + + + +--*/ + +#ifndef _LIST_H_INCLUDED +#define _LIST_H_INCLUDED + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +typedef struct _LIST_ENTRY { + struct _LIST_ENTRY *Flink; + struct _LIST_ENTRY *Blink; +} LIST_ENTRY, *PLIST_ENTRY; + +// +// VOID +// InitializeListHead( +// PLIST_ENTRY ListHead +// ); +// + +#define InitializeListHead(ListHead) (\ + (ListHead)->Flink = (ListHead)->Blink = (ListHead)) + +// +// BOOLEAN +// IsListEmpty( +// PLIST_ENTRY ListHead +// ); +// + +#define IsListEmpty(ListHead) \ + ((ListHead)->Flink == (ListHead)) + +// +// PLIST_ENTRY +// RemoveHeadList( +// PLIST_ENTRY ListHead +// ); +// + +#define RemoveHeadList(ListHead) \ + (ListHead)->Flink;\ + {RemoveEntryList((ListHead)->Flink)} + +// +// PLIST_ENTRY +// RemoveTailList( +// PLIST_ENTRY ListHead +// ); +// + +#define RemoveTailList(ListHead) \ + (ListHead)->Blink;\ + {RemoveEntryList((ListHead)->Blink)} + +// +// VOID +// RemoveEntryList( +// PLIST_ENTRY Entry +// ); +// + +#define RemoveEntryList(Entry) {\ + PLIST_ENTRY _EX_Blink;\ + PLIST_ENTRY _EX_Flink;\ + _EX_Flink = (Entry)->Flink;\ + _EX_Blink = (Entry)->Blink;\ + _EX_Blink->Flink = _EX_Flink;\ + _EX_Flink->Blink = _EX_Blink;\ + } + +// +// VOID +// InsertTailList( +// PLIST_ENTRY ListHead, +// PLIST_ENTRY Entry +// ); +// + +#define InsertTailList(ListHead,Entry) {\ + PLIST_ENTRY _EX_Blink;\ + PLIST_ENTRY _EX_ListHead;\ + _EX_ListHead = (ListHead);\ + _EX_Blink = _EX_ListHead->Blink;\ + (Entry)->Flink = _EX_ListHead;\ + (Entry)->Blink = _EX_Blink;\ + _EX_Blink->Flink = (Entry);\ + _EX_ListHead->Blink = (Entry);\ + } + +// +// VOID +// InsertHeadList( +// PLIST_ENTRY ListHead, +// PLIST_ENTRY Entry +// ); +// + +#define InsertHeadList(ListHead,Entry) {\ + PLIST_ENTRY _EX_Flink;\ + PLIST_ENTRY _EX_ListHead;\ + _EX_ListHead = (ListHead);\ + _EX_Flink = _EX_ListHead->Flink;\ + (Entry)->Flink = _EX_Flink;\ + (Entry)->Blink = _EX_ListHead;\ + _EX_Flink->Blink = (Entry);\ + _EX_ListHead->Flink = (Entry);\ + } + +#define CONTAINING_RECORD(address, type, field) ((type *)( \ + (PCHAR)(address) - \ + (ULONG_PTR)(&((type *)0)->field))) + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // _LIST_H_INCLUDED + diff --git a/src/pal/src/include/pal/locale.h b/src/pal/src/include/pal/locale.h new file mode 100644 index 0000000000..f59ce2e174 --- /dev/null +++ b/src/pal/src/include/pal/locale.h @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + locale.h + +Abstract: + + Prototypes for codepage initialization, and control of the readwrite locks + for systems that use them. + +Revision History: + + + +--*/ + +#ifndef _PAL_LOCALE_H_ +#define _PAL_LOCALE_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +#if HAVE_LOWERCASE_ISO_NAME +#define ISO_NAME(region, encoding, part) region ".iso" encoding part +#elif HAVE_UNDERSCORE_ISO_NAME +#define ISO_NAME(region, encoding, part) region ".ISO_" encoding "-" part +#else +#define ISO_NAME(region, encoding, part) region ".ISO" encoding "-" part +#endif + +#if HAVE_COREFOUNDATION +#define CF_EXCLUDE_CSTD_HEADERS +#include <CoreFoundation/CoreFoundation.h> +#endif // HAVE_COREFOUNDATION + +#if HAVE_COREFOUNDATION +#if !ENABLE_DOWNLEVEL_FOR_NLS +BOOL LocaleInitialize( void ); +void LocaleCleanup( void ); +#endif // !ENABLE_DOWNLEVEL_FOR_NLS + +typedef +struct _CP_MAPPING +{ + UINT nCodePage; /* Code page identifier. */ + CFStringEncoding nCFEncoding; /* The equivalent CFString encoding. */ + UINT nMaxByteSize; /* The max byte size of any character. */ + BYTE LeadByte[ MAX_LEADBYTES ]; /* The lead byte array. */ +} CP_MAPPING; +#elif HAVE_PTHREAD_RWLOCK_T +typedef +struct _CP_MAPPING +{ + UINT nCodePage; // Code page identifier. + LPCSTR lpBSDEquivalent; // The equivalent BSD locale identifier. + UINT nMaxByteSize; // The max byte size of any character. + BYTE LeadByte[ MAX_LEADBYTES ]; // The lead byte array. +} CP_MAPPING; +#else +#error Insufficient platform support for text encodings +#endif +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* _PAL_LOCALE_H_ */ diff --git a/src/pal/src/include/pal/malloc.hpp b/src/pal/src/include/pal/malloc.hpp new file mode 100644 index 0000000000..c7333419a7 --- /dev/null +++ b/src/pal/src/include/pal/malloc.hpp @@ -0,0 +1,152 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + pal/malloc.hpp + +Abstract: + Declarations for suspension safe memory allocation functions + + + +--*/ + +#ifndef _MALLOC_HPP +#define _MALLOC_HPP + +#include "pal/corunix.hpp" +#include "pal/thread.hpp" + +#include <stdarg.h> +#include <stdlib.h> + +extern "C" +{ + void * + __cdecl + PAL_realloc( + void* pvMemblock, + size_t szSize + ); + + void * + __cdecl + PAL_malloc( + size_t szSize + ); + + void + __cdecl + PAL_free( + void *pvMem + ); + + char * + __cdecl + PAL__strdup( + const char *c_szStr + ); +} + +inline void* operator new(size_t, void* p) throw () { return p; } +inline void* operator new[](size_t, void* p) throw () { return p; } + +namespace CorUnix{ + + void * + InternalRealloc( + void *pvMemblock, + size_t szSize + ); + + void * + InternalMalloc( + size_t szSize + ); + + // Define common code for "new" style allocators below. +#define INTERNAL_NEW_COMMON() \ + T *pMem = (T*)InternalMalloc(sizeof(T)); \ + if (pMem == NULL) \ + return NULL; + + // Define "new" style allocators (which allocate then call a constructor) for different numbers of + // constructor arguments. Added based on usage. + + // Default constructor (0 args) case. + template<class T> + T* InternalNew() + { + INTERNAL_NEW_COMMON(); + return new (pMem) T(); + } + + // 2 args case. + template<class T, class A1, class A2> + T* InternalNew(A1 arg1, A2 arg2) + { + INTERNAL_NEW_COMMON(); + return new (pMem) T(arg1, arg2); + } + + // 4 args case. + template<class T, class A1, class A2, class A3, class A4> + T* InternalNew(A1 arg1, A2 arg2, A3 arg3, A4 arg4) + { + INTERNAL_NEW_COMMON(); + return new (pMem) T(arg1, arg2, arg3, arg4); + } + + // 5 args case. + template<class T, class A1, class A2, class A3, class A4, class A5> + T* InternalNew(A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5) + { + INTERNAL_NEW_COMMON(); + return new (pMem) T(arg1, arg2, arg3, arg4, arg5); + } + + template<class T> T* InternalNewArray(size_t cElements) + { + size_t cbSize = (cElements * sizeof(T)) + sizeof(size_t); + T *pMem; + + pMem = (T*)InternalMalloc(cbSize); + + if (pMem == NULL) + return NULL; + + *(size_t*)pMem = cElements; + pMem = (T*)((size_t*)pMem + 1); + + return new (pMem) T[cElements](); + } + + template<class T> void InternalDelete(T *p) + { + if (p) + { + p->~T(); + free(p); + } + } + + template<class T> void InternalDeleteArray(T *p) + { + if (p) + { + size_t *pRealMem = (size_t*)p - 1; + size_t cElements = *pRealMem; + for (size_t i = 0; i < cElements; i++) + p[i].~T(); + free(pRealMem); + } + } +} + +#endif // _MALLOC_HPP diff --git a/src/pal/src/include/pal/map.h b/src/pal/src/include/pal/map.h new file mode 100644 index 0000000000..96f538fbd1 --- /dev/null +++ b/src/pal/src/include/pal/map.h @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/map.h + +Abstract: + + Header file for file mapping functions. + + + +--*/ + +#ifndef _PAL_MAP_H_ +#define _PAL_MAP_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/*++ +Function : + MAPGetRegionInfo + + Parameters: + lpAddress: pointer to the starting memory location, not necessary + to be rounded to the page location + + lpBuffer: if this function finds information about the specified address, + the information is stored in this struct + + Note: This function is to be used in virtual.c + + Returns TRUE if this function finds information about the specified address +--*/ + +BOOL MAPGetRegionInfo(LPVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* _PAL_MAP_H_ */ + diff --git a/src/pal/src/include/pal/map.hpp b/src/pal/src/include/pal/map.hpp new file mode 100644 index 0000000000..854e6c549a --- /dev/null +++ b/src/pal/src/include/pal/map.hpp @@ -0,0 +1,209 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/map.hpp + +Abstract: + + Header file for file mapping functions. + + + +--*/ + +#ifndef _PAL_MAP_H_ +#define _PAL_MAP_H_ + +#include "corunix.hpp" +#include <sys/param.h> + +extern "C" +{ +#include "list.h" + +#ifndef NO_INO +#define NO_INO ((ino_t)-1) +#endif + + /*++ + Function : + MapInitialize + + Initialize the critical sections. + + Return value: + TRUE if initialization succeeded + FALSE otherwise + --*/ + BOOL MAPInitialize( void ); + + /*++ + Function : + MapCleanup + + Deletes the critical sections. + + --*/ + void MAPCleanup( void ); + + /*++ + Function : + MAPGetRegionInfo + + Parameters: + lpAddress: pointer to the starting memory location, not necessary + to be rounded to the page location + + lpBuffer: if this function finds information about the specified address, + the information is stored in this struct + + Note: This function is to be used in virtual.c + + Returns TRUE if this function finds information about the specified address + --*/ + + BOOL MAPGetRegionInfo(LPVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer); + + /*++ + MAPMapPEFile - + + Map a PE format file into memory like Windows LoadLibrary() would do. + Doesn't apply base relocations if the function is relocated. + + Parameters: + IN hFile - file to map + + Return value: + non-NULL - the base address of the mapped image + NULL - error, with last error set. + --*/ + + void * MAPMapPEFile(HANDLE hFile); + + /*++ + Function : + MAPUnmapPEFile - unmap a PE file, and remove it from the recorded list of PE files mapped + + returns TRUE if successful, FALSE otherwise + --*/ + BOOL MAPUnmapPEFile(LPCVOID lpAddress); +} + +namespace CorUnix +{ + extern CObjectType otFileMapping; + +#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS + typedef struct _NativeMapHolder + { + Volatile<LONG> ref_count; + LPVOID address; + SIZE_T size; + SIZE_T offset; /* for future use */ + } NativeMapHolder; +#endif + + /* Process specific information. This + structure is not stored in shared memory.*/ + typedef struct _MVL + { + LIST_ENTRY Link; + + // + // Each MVL entry holds a reference to its parent file + // mapping object. + // + + IPalObject *pFileMapping; + +#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS + NativeMapHolder * pNMHolder; /* Ref-counted holder for memory mapping */ + dev_t MappedFileDevNum; /* ID of device containing the file to be mapped */ + ino_t MappedFileInodeNum; /* Inode number of file to be mapped. + These two fields are used used to uniquely + identify files on systems that do not allow + more than one shared mmapping per region of + physical file, per process */ +#endif + LPVOID lpAddress; /* The pointer to the mapped memory. */ + SIZE_T NumberOfBytesToMap; /* Number of bytes to map. */ + DWORD dwDesiredAccess; /* Desired access. */ + LPVOID lpPEBaseAddress; /* If this mapping is part of a PE file mapping, this is the + base address pointer of the PE file (used to find all + parts of the PE file mapping to allow PE file unload). + Otherwise, it is NULL. */ + } MAPPED_VIEW_LIST, * PMAPPED_VIEW_LIST; + + class CFileMappingImmutableData + { + public: + CHAR szFileName[MAXPATHLEN]; + UINT MaxSize; // The max size of the file mapping object + DWORD flProtect; // Protection desired for the file view + BOOL bPALCreatedTempFile; // TRUE if it's a PAL created file + DWORD dwDesiredAccessWhenOpened; // FILE_MAP_WRITE etc + }; + + class CFileMappingProcessLocalData + { + public: + INT UnixFd; /* File descriptor. */ + +#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS + dev_t MappedFileDevNum; /* ID of device containing the file to be mapped */ + ino_t MappedFileInodeNum; /* Inode number of file to be mapped. + These two fields are used used to uniquely + identify files on systems that do not allow + more than one shared mmapping per region of + physical file, per process */ +#endif + }; + + PAL_ERROR + InternalCreateFileMapping( + CPalThread *pThread, + HANDLE hFile, + LPSECURITY_ATTRIBUTES lpFileMappingAttributes, + DWORD flProtect, + DWORD dwMaximumSizeHigh, + DWORD dwMaximumSizeLow, + LPCWSTR lpName, + HANDLE *phMapping + ); + + PAL_ERROR + InternalOpenFileMapping( + CPalThread *pThread, + DWORD dwDesiredAccess, + BOOL bInheritHandle, + LPCWSTR lpName, + HANDLE *phMapping + ); + + PAL_ERROR + InternalMapViewOfFile( + CPalThread *pThread, + HANDLE hFileMappingObject, + DWORD dwDesiredAccess, + DWORD dwFileOffsetHigh, + DWORD dwFileOffsetLow, + SIZE_T dwNumberOfBytesToMap, + LPVOID *ppvBaseAddress + ); + + PAL_ERROR + InternalUnmapViewOfFile( + CPalThread *pThread, + LPCVOID lpBaseAddress + ); + +} + +#endif /* _PAL_MAP_H_ */ diff --git a/src/pal/src/include/pal/misc.h b/src/pal/src/include/pal/misc.h new file mode 100644 index 0000000000..65d59aee60 --- /dev/null +++ b/src/pal/src/include/pal/misc.h @@ -0,0 +1,83 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/misc.h + +Abstract: + Header file for the initialization and clean up functions + for the misc Win32 functions + + + +--*/ + +#ifndef __MISC_H_ +#define __MISC_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/*++ +Function : + + PAL_rand + + Calls rand and mitigates the difference between RAND_MAX + on Windows and FreeBSD. +--*/ +int __cdecl PAL_rand(void); + +/*++ +Function : + + PAL_time +--*/ +PAL_time_t __cdecl PAL_time(PAL_time_t*); + +/*++ +Function: +TIMEInitialize + +Return value: +TRUE if initialize succeeded +FALSE otherwise + +--*/ +BOOL TIMEInitialize( void ); + +/*++ +Function : + MsgBoxInitialize + + Initialize the critical sections. + +Return value: + TRUE if initialize succeeded + FALSE otherwise + +--*/ +BOOL MsgBoxInitialize( void ); + +/*++ +Function : + MsgBoxCleanup + + Deletes the critical sections. + +--*/ +void MsgBoxCleanup( void ); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* __MISC_H_ */ diff --git a/src/pal/src/include/pal/module.h b/src/pal/src/include/pal/module.h new file mode 100644 index 0000000000..95fa605c21 --- /dev/null +++ b/src/pal/src/include/pal/module.h @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/module.h + +Abstract: + Header file for modle management utilities. + + + +--*/ + +#ifndef _PAL_MODULE_H_ +#define _PAL_MODULE_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +typedef BOOL (__stdcall *PDLLMAIN)(HINSTANCE, DWORD, LPVOID); /* entry point of module */ +typedef HINSTANCE (PALAPI *PREGISTER_MODULE)(LPCSTR); /* used to create the HINSTANCE for above DLLMain entry point */ +typedef VOID (PALAPI *PUNREGISTER_MODULE)(HINSTANCE); /* used to cleanup the HINSTANCE for above DLLMain entry point */ + +typedef struct _MODSTRUCT +{ + HMODULE self; /* circular reference to this module */ + void *dl_handle; /* handle returned by dlopen() */ + HINSTANCE hinstance; /* handle returned by PAL_RegisterLibrary */ + LPWSTR lib_name; /* full path of module */ + INT refcount; /* reference count */ + /* -1 means infinite reference count - module is never released */ + BOOL threadLibCalls; /* TRUE for DLL_THREAD_ATTACH/DETACH notifications enabled, FALSE if they are disabled */ + +#if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN + ino_t inode; + dev_t device; +#endif + + PDLLMAIN pDllMain; /* entry point of module */ + + /* reference to next and previous modules in list (in load order) */ + struct _MODSTRUCT *next; + struct _MODSTRUCT *prev; +} MODSTRUCT; + + +/*++ +Function : + LOADInitializeModules + + Initialize the process-wide list of modules + +Parameters : + None + +Return value : + TRUE on success, FALSE on failure + +--*/ +BOOL LOADInitializeModules(); + +/*++ +Function : + LOADSetExeName + + Set the exe name path + +Parameters : + LPWSTR man exe path and name + +Return value : + TRUE if initialization succeedded + FALSE otherwise + +--*/ +BOOL LOADSetExeName(LPWSTR name); + +/*++ +Function : + LOADCallDllMain + + Call DllMain for all modules (that have one) with the given "fwReason" + +Parameters : + DWORD dwReason : parameter to pass down to DllMain, one of DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH, + DLL_THREAD_ATTACH, DLL_THREAD_DETACH + + LPVOID lpReserved : parameter to pass down to DllMain + If dwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for dynamic loads and non-NULL for static loads. + If dwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if DllMain has been called by using FreeLibrary + and non-NULL if DllMain has been called during process termination. + +(no return value) + +Notes : + This is used to send DLL_THREAD_*TACH messages to modules +--*/ +void LOADCallDllMain(DWORD dwReason, LPVOID lpReserved); + +/*++ +Function: + LockModuleList + +Abstract + Enter the critical section associated to the module list + +Parameter + void + +Return + void +--*/ +void LockModuleList(); + +/*++ +Function: + UnlockModuleList + +Abstract + Leave the critical section associated to the module list + +Parameter + void + +Return + void +--*/ +void UnlockModuleList(); + +/*++ +Function: + PAL_LOADLoadPEFile + +Abstract + Loads a PE file into memory. Properly maps all of the sections in the PE file. Returns a pointer to the + loaded base. + +Parameters: + IN hFile - The file to load + +Return value: + A valid base address if successful. + 0 if failure +--*/ +void * PAL_LOADLoadPEFile(HANDLE hFile); + +/*++ + PAL_LOADUnloadPEFile + + Unload a PE file that was loaded by PAL_LOADLoadPEFile(). + +Parameters: + IN ptr - the file pointer returned by PAL_LOADLoadPEFile() + +Return value: + TRUE - success + FALSE - failure (incorrect ptr, etc.) +--*/ +BOOL PAL_LOADUnloadPEFile(void * ptr); + +/*++ + LOADInitializeCoreCLRModule + + Run the initialization methods for CoreCLR module. + +Parameters: + None + +Return value: + TRUE if successful + FALSE if failure +--*/ +BOOL LOADInitializeCoreCLRModule(); + +/*++ +Function : + LOADGetPalLibrary + + Load and initialize the PAL module. + +Parameters : + None + +Return value : + handle to loaded module + +--*/ +MODSTRUCT *LOADGetPalLibrary(); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* _PAL_MODULE_H_ */ + diff --git a/src/pal/src/include/pal/modulename.h b/src/pal/src/include/pal/modulename.h new file mode 100644 index 0000000000..70b0a610dc --- /dev/null +++ b/src/pal/src/include/pal/modulename.h @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/modulename.h + +Abstract: + Header file for functions to get the name of a module + +Revision History: + + + +--*/ + +#ifndef _PAL_MODULENAME_H_ +#define _PAL_MODULENAME_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +const char *PAL_dladdr(LPVOID ProcAddress); +#if defined(_AIX) +int GetLibRotorNameViaLoadQuery(LPSTR pszBuf); +#endif + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /*_PAL_MODULENAME_H_*/ diff --git a/src/pal/src/include/pal/mutex.hpp b/src/pal/src/include/pal/mutex.hpp new file mode 100644 index 0000000000..6a46689d7d --- /dev/null +++ b/src/pal/src/include/pal/mutex.hpp @@ -0,0 +1,191 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + mutex.hpp + +Abstract: + + Mutex object structure definition. + + + +--*/ + +#ifndef _PAL_MUTEX_H_ +#define _PAL_MUTEX_H_ + +#include "corunix.hpp" +#include "sharedmemory.h" + +#include <pthread.h> + +namespace CorUnix +{ + extern CObjectType otMutex; + extern CObjectType otNamedMutex; + + PAL_ERROR + InternalCreateMutex( + CPalThread *pThread, + LPSECURITY_ATTRIBUTES lpMutexAttributes, + BOOL bInitialOwner, + LPCSTR lpName, + HANDLE *phMutex + ); + + PAL_ERROR + InternalReleaseMutex( + CPalThread *pThread, + HANDLE hMutex + ); + + PAL_ERROR + InternalOpenMutex( + CPalThread *pThread, + DWORD dwDesiredAccess, + BOOL bInheritHandle, + LPCSTR lpName, + HANDLE *phMutex + ); + +} + +#define SYNCSPINLOCK_F_ASYMMETRIC 1 + +#define SPINLOCKInit(lock) (*(lock) = 0) +#define SPINLOCKDestroy SPINLOCKInit + +void SPINLOCKAcquire (LONG * lock, unsigned int flags); +void SPINLOCKRelease (LONG * lock); +DWORD SPINLOCKTryAcquire (LONG * lock); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Named mutex + +// Temporarily disabling usage of pthread process-shared mutexes on ARM/ARM64 due to functional issues that cannot easily be +// detected with code due to hangs. See https://github.com/dotnet/coreclr/issues/5456. +#if HAVE_FULLY_FEATURED_PTHREAD_MUTEXES && HAVE_FUNCTIONAL_PTHREAD_ROBUST_MUTEXES && !(defined(_ARM_) || defined(_ARM64_)) + #define NAMED_MUTEX_USE_PTHREAD_MUTEX 1 +#else + #define NAMED_MUTEX_USE_PTHREAD_MUTEX 0 +#endif + +enum class NamedMutexError : DWORD +{ + MaximumRecursiveLocksReached = ERROR_NOT_ENOUGH_MEMORY, + ThreadHasNotAcquiredMutex = ERROR_NOT_OWNER, + Unknown = ERROR_NOT_ENOUGH_MEMORY +}; + +enum class MutexTryAcquireLockResult +{ + AcquiredLock, + AcquiredLockButMutexWasAbandoned, + TimedOut +}; + +#if NAMED_MUTEX_USE_PTHREAD_MUTEX +class MutexHelpers +{ +public: + static void InitializeProcessSharedRobustRecursiveMutex(pthread_mutex_t *mutex); + static void DestroyMutex(pthread_mutex_t *mutex); + + static MutexTryAcquireLockResult TryAcquireLock(pthread_mutex_t *mutex, DWORD timeoutMilliseconds); + static void ReleaseLock(pthread_mutex_t *mutex); +}; +#endif // NAMED_MUTEX_USE_PTHREAD_MUTEX + +class NamedMutexSharedData +{ +private: +#if NAMED_MUTEX_USE_PTHREAD_MUTEX + pthread_mutex_t m_lock; +#else // !NAMED_MUTEX_USE_PTHREAD_MUTEX + UINT32 m_timedWaiterCount; +#endif // NAMED_MUTEX_USE_PTHREAD_MUTEX + UINT32 m_lockOwnerProcessId; + UINT64 m_lockOwnerThreadId; + bool m_isAbandoned; + +public: + NamedMutexSharedData(); + ~NamedMutexSharedData(); + +#if NAMED_MUTEX_USE_PTHREAD_MUTEX +public: + pthread_mutex_t *GetLock(); +#else // !NAMED_MUTEX_USE_PTHREAD_MUTEX +public: + bool HasAnyTimedWaiters() const; + void IncTimedWaiterCount(); + void DecTimedWaiterCount(); +#endif // NAMED_MUTEX_USE_PTHREAD_MUTEX + +public: + bool IsAbandoned() const; + void SetIsAbandoned(bool isAbandoned); + +public: + bool IsLockOwnedByAnyThread() const; + bool IsLockOwnedByCurrentThread() const; + void SetLockOwnerToCurrentThread(); + void ClearLockOwner(); +}; + +class NamedMutexProcessData : public SharedMemoryProcessDataBase +{ +private: + static const UINT8 SyncSystemVersion; + static const DWORD PollLoopMaximumSleepMilliseconds; + +private: + SharedMemoryProcessDataHeader *m_processDataHeader; + NamedMutexSharedData *m_sharedData; + SIZE_T m_lockCount; +#if !NAMED_MUTEX_USE_PTHREAD_MUTEX + HANDLE m_processLockHandle; + int m_sharedLockFileDescriptor; +#endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX + CorUnix::CPalThread *m_lockOwnerThread; + NamedMutexProcessData *m_nextInThreadOwnedNamedMutexList; + +public: + static SharedMemoryProcessDataHeader *CreateOrOpen(LPCSTR name, bool acquireLockIfCreated, bool *createdRef); + static SharedMemoryProcessDataHeader *Open(LPCSTR name); +private: + static SharedMemoryProcessDataHeader *CreateOrOpen(LPCSTR name, bool createIfNotExist, bool acquireLockIfCreated, bool *createdRef); + +public: + NamedMutexProcessData( + SharedMemoryProcessDataHeader *processDataHeader + #if !NAMED_MUTEX_USE_PTHREAD_MUTEX + , + int sharedLockFileDescriptor + #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX + ); + virtual void Close(bool isAbruptShutdown, bool releaseSharedData) override; + +private: + NamedMutexSharedData *GetSharedData() const; + void SetLockOwnerThread(CorUnix::CPalThread *lockOwnerThread); +public: + NamedMutexProcessData *GetNextInThreadOwnedNamedMutexList() const; + void SetNextInThreadOwnedNamedMutexList(NamedMutexProcessData *next); + +public: + MutexTryAcquireLockResult TryAcquireLock(DWORD timeoutMilliseconds); + void ReleaseLock(); + void Abandon(); +private: + void ActuallyReleaseLock(); +}; + +#endif //_PAL_MUTEX_H_ diff --git a/src/pal/src/include/pal/palinternal.h b/src/pal/src/include/pal/palinternal.h new file mode 100644 index 0000000000..7348192e6d --- /dev/null +++ b/src/pal/src/include/pal/palinternal.h @@ -0,0 +1,696 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + palinternal.h + +Abstract: + + Rotor Platform Adaptation Layer (PAL) header file used by source + file part of the PAL implementation. This is a wrapper over + unix/inc/pal.h. It allows avoiding name collisions when including + system header files, and it allows redirecting calls to 'standard' functions + to their PAL counterpart + +Details : + +A] Rationale (see B] for the quick recipe) +There are 2 types of namespace collisions that must be handled. + +1) standard functions declared in pal.h, which do not need to be + implemented in the PAL because the system's implementation is sufficient. + + (examples : memcpy, strlen, fclose) + + The problem with these is that a prototype for them is provided both in + pal.h and in a system header (stdio.h, etc). If a PAL file needs to + include the files containing both prototypes, the compiler may complain + about the multiple declarations. + + To avoid this, the inclusion of pal.h must be wrapped in a + #define/#undef pair, which will effectiveily "hide" the pal.h + declaration by renaming it to something else. this is done by palinternal.h + in this way : + + #define some_function DUMMY_some_function + #include <pal.h> + #undef some_function + + when a PAL source file includes palinternal.h, it will see a prototype for + DUMMY_some_function instead of some_function; so when it includes the + system header with the "real" prototype, no collision occurs. + + (note : technically, no functions should ever be treated this way, all + system functions should be wrapped according to method 2, so that call + logging through ENTRY macros is done for all functions n the PAL. However + this reason alone is not currently considered enough to warrant a wrapper) + +2) standard functions which must be reimplemented by the PAL, because the + system's implementation does not offer suitable functionnality. + + (examples : widestring functions, networking) + + Here, the problem is more complex. The PAL must provide functions with the + same name as system functions. Due to the nature of Unix dynamic linking, + if this is done, the PAL's implementation will effectively mask the "real" + function, so that all calls are directed to it. This makes it impossible for + a function to be implemented as calling its counterpart in the system, plus + some extra work, because instead of calling the system's implementation, the + function would only call itself in an infinitely recursing nightmare. Even + worse, if by bad luck the system libraries attempt to call the function for + which the PAL provides an implementation, it is the PAL's version that will + be called. + It is therefore necessary to give the PAL's implementation of such functions + a different name. However, PAL consumers (applications built on top of the + PAL) must be able to call the function by its 'official' name, not the PAL's + internal name. + This can be done with some more macro magic, by #defining the official name + to the internal name *in pal.h*. : + + #define some_function PAL_some_function + + This way, while PAL consumer code can use the official name, it is the + internal name that wil be seen at compile time. + However, one extra step is needed. While PAL consumers must use the PAL's + implementation of these functions, the PAL itself must still have access to + the "real" functions. This is done by #undefining in palinternal.h the names + #defined in pal.h : + + #include <pal.h> + #undef some_function. + + At this point, code in the PAL implementation can access *both* its own + implementation of the function (with PAL_some_function) *and* the system's + implementation (with some_function) + + [side note : for the Win32 PAL, this can be accomplished without touching + pal.h. In Windows, symbols in in dynamic libraries are resolved at + compile time. if an application that uses some_function is only linked to + pal.dll, some_function will be resolved to the version in that DLL, + even if other DLLs in the system provide other implementations. In addition, + the function in the DLL can actually have a different name (e.g. + PAL_some_function), to which the 'official' name is aliased when the DLL + is compiled. All this is not possible with Unix dynamic linking, where + symbols are resolved at run-time in a first-found-first-used order. A + module may end up using the symbols from a module it was never linked with, + simply because that module was located somewhere in the dependency chain. ] + + It should be mentionned that even if a function name is not documented as + being implemented in the system, it can still cause problems if it exists. + This is especially a problem for functions in the "reserved" namespace + (names starting with an underscore : _exit, etc). (We shouldn't really be + implementing functions with such a name, but we don't really have a choice) + If such a case is detected, it should be wrapped according to method 2 + + Note that for all this to work, it is important for the PAL's implementation + files to #include palinternal.h *before* any system files, and to never + include pal.h directly. + +B] Procedure for name conflict resolution : + +When adding a function to pal.h, which is implemented by the system and +which does not need a different implementation : + +- add a #define function_name DUMMY_function_name to palinternal.h, after all + the other DUMMY_ #defines (above the #include <pal.h> line) +- add the function's prototype to pal.h (if that isn't already done) +- add a #undef function_name to palinternal.h near all the other #undefs + (after the #include <pal.h> line) + +When overriding a system function with the PAL's own implementation : + +- add a #define function_name PAL_function_name to pal.h, somewhere + before the function's prototype, inside a #ifndef _MSCVER/#endif pair + (to avoid affecting the Win32 build) +- add a #undef function_name to palinternal.h near all the other #undefs + (after the #include <pal.h> line) +- implement the function in the pal, naming it PAL_function_name +- within the PAL, call PAL_function_name() to call the PAL's implementation, +function_name() to call the system's implementation + + + +--*/ + +#ifndef _PAL_INTERNAL_H_ +#define _PAL_INTERNAL_H_ + +#define PAL_IMPLEMENTATION + +/* Include our configuration information so it's always present when + compiling PAL implementation files. */ +#include "config.h" + +#ifdef DEBUG +#define _ENABLE_DEBUG_MESSAGES_ 1 +#else +#define _ENABLE_DEBUG_MESSAGES_ 0 +#endif + +#ifdef PAL_PERF +#include "pal_perf.h" +#endif + +/* C runtime functions needed to be renamed to avoid duplicate definition + of those functions when including standard C header files */ +#define div DUMMY_div +#define div_t DUMMY_div_t +#if !defined(_DEBUG) +#define memcpy DUMMY_memcpy +#endif //!defined(_DEBUG) +#define memcmp DUMMY_memcmp +#define memset DUMMY_memset +#define memmove DUMMY_memmove +#define memchr DUMMY_memchr +#define strlen DUMMY_strlen +#define strnlen DUMMY_strnlen +#define stricmp DUMMY_stricmp +#define strstr DUMMY_strstr +#define strcmp DUMMY_strcmp +#define strcat DUMMY_strcat +#define strncat DUMMY_strncat +#define strcpy DUMMY_strcpy +#define strcspn DUMMY_strcspn +#define strncmp DUMMY_strncmp +#define strncpy DUMMY_strncpy +#define strchr DUMMY_strchr +#define strrchr DUMMY_strrchr +#define strpbrk DUMMY_strpbrk +#define strtod DUMMY_strtod +#define strspn DUMMY_strspn +#if HAVE__SNPRINTF +#define _snprintf DUMMY__snprintf +#endif /* HAVE__SNPRINTF */ +#if HAVE__SNWPRINTF +#define _snwprintf DUMMY__snwprintf +#endif /* HAVE__SNWPRINTF */ +#define tolower DUMMY_tolower +#define toupper DUMMY_toupper +#define islower DUMMY_islower +#define isupper DUMMY_isupper +#define isprint DUMMY_isprint +#define isdigit DUMMY_isdigit +#define srand DUMMY_srand +#define atoi DUMMY_atoi +#define atof DUMMY_atof +#define tm PAL_tm +#define size_t DUMMY_size_t +#define time_t PAL_time_t +#define va_list DUMMY_va_list +#define abs DUMMY_abs +#define llabs DUMMY_llabs +#define ceil DUMMY_ceil +#define cos DUMMY_cos +#define cosh DUMMY_cosh +#define fabs DUMMY_fabs +#define floor DUMMY_floor +#define fmod DUMMY_fmod +#define modf DUMMY_modf +#define sin DUMMY_sin +#define sinh DUMMY_sinh +#define sqrt DUMMY_sqrt +#define tan DUMMY_tan +#define tanh DUMMY_tanh +#define fabsf DUMMY_fabsf +#define fmodf DUMMY_fmodf +#define modff DUMMY_modff + +/* RAND_MAX needed to be renamed to avoid duplicate definition when including + stdlib.h header files. PAL_RAND_MAX should have the same value as RAND_MAX + defined in pal.h */ +#define PAL_RAND_MAX 0x7fff + +/* The standard headers define isspace and isxdigit as macros and functions, + To avoid redefinition problems, undefine those macros. */ +#ifdef isspace +#undef isspace +#endif +#ifdef isxdigit +#undef isxdigit +#endif +#ifdef isalpha +#undef isalpha +#endif +#ifdef isalnum +#undef isalnum +#endif +#define isspace DUMMY_isspace +#define isxdigit DUMMY_isxdigit +#define isalpha DUMMY_isalpha +#define isalnum DUMMY_isalnum + +#ifdef stdin +#undef stdin +#endif +#ifdef stdout +#undef stdout +#endif +#ifdef stderr +#undef stderr +#endif + +#ifdef SCHAR_MIN +#undef SCHAR_MIN +#endif +#ifdef SCHAR_MAX +#undef SCHAR_MAX +#endif +#ifdef SHRT_MIN +#undef SHRT_MIN +#endif +#ifdef SHRT_MAX +#undef SHRT_MAX +#endif +#ifdef UCHAR_MAX +#undef UCHAR_MAX +#endif +#ifdef USHRT_MAX +#undef USHRT_MAX +#endif +#ifdef ULONG_MAX +#undef ULONG_MAX +#endif +#ifdef LONG_MIN +#undef LONG_MIN +#endif +#ifdef LONG_MAX +#undef LONG_MAX +#endif +#ifdef RAND_MAX +#undef RAND_MAX +#endif +#ifdef DBL_MAX +#undef DBL_MAX +#endif +#ifdef FLT_MAX +#undef FLT_MAX +#endif +#ifdef __record_type_class +#undef __record_type_class +#endif +#ifdef __real_type_class +#undef __real_type_class +#endif + +// The standard headers define va_start and va_end as macros, +// To avoid redefinition problems, undefine those macros. +#ifdef va_start +#undef va_start +#endif +#ifdef va_end +#undef va_end +#endif +#ifdef va_copy +#undef va_copy +#endif + + +#ifdef _VAC_ +#define wchar_16 wchar_t +#else +#define wchar_t wchar_16 +#endif // _VAC_ + +#define ptrdiff_t PAL_ptrdiff_t +#define intptr_t PAL_intptr_t +#define uintptr_t PAL_uintptr_t +#define timeval PAL_timeval +#define FILE PAL_FILE + +#include "pal.h" +#include "palprivate.h" + +#include "mbusafecrt.h" + +#ifdef _VAC_ +#undef CHAR_BIT +#undef va_arg +#endif + +#if !defined(_MSC_VER) && defined(FEATURE_PAL) && defined(_WIN64) +#undef _BitScanForward64 +#endif + +/* pal.h defines alloca(3) as a compiler builtin. + Redefining it to native libc will result in undefined breakage because + a compiler is allowed to make assumptions about the stack and frame + pointers. */ + +/* Undef all functions and types previously defined so those functions and + types could be mapped to the C runtime and socket implementation of the + native OS */ +#undef exit +#undef atexit +#undef div +#undef div_t +#if !defined(_DEBUG) +#undef memcpy +#endif //!defined(_DEBUG) +#undef memcmp +#undef memset +#undef memmove +#undef memchr +#undef strlen +#undef strnlen +#undef stricmp +#undef strstr +#undef strcmp +#undef strcat +#undef strcspn +#undef strncat +#undef strcpy +#undef strncmp +#undef strncpy +#undef strchr +#undef strrchr +#undef strpbrk +#undef strtoul +#undef strtod +#undef strspn +#undef strtok +#undef strdup +#undef tolower +#undef toupper +#undef islower +#undef isupper +#undef isprint +#undef isdigit +#undef isspace +#undef iswdigit +#undef iswxdigit +#undef iswalpha +#undef iswprint +#undef isxdigit +#undef isalpha +#undef isalnum +#undef atoi +#undef atol +#undef atof +#undef malloc +#undef realloc +#undef free +#undef qsort +#undef bsearch +#undef time +#undef tm +#undef localtime +#undef mktime +#undef FILE +#undef fclose +#undef setbuf +#undef fopen +#undef fread +#undef feof +#undef ferror +#undef ftell +#undef fflush +#undef fwrite +#undef fgets +#undef fgetws +#undef fputc +#undef putchar +#undef fputs +#undef fseek +#undef fgetpos +#undef fsetpos +#undef getcwd +#undef getc +#undef fgetc +#undef ungetc +#undef _flushall +#undef setvbuf +#undef mkstemp +#undef rename +#undef unlink +#undef size_t +#undef time_t +#undef va_list +#undef va_start +#undef va_end +#undef va_copy +#undef stdin +#undef stdout +#undef stderr +#undef abs +#undef labs +#undef llabs +#undef acos +#undef asin +#undef atan +#undef atan2 +#undef ceil +#undef cos +#undef cosh +#undef exp +#undef fabs +#undef floor +#undef fmod +#undef log +#undef log10 +#undef modf +#undef pow +#undef sin +#undef sinh +#undef sqrt +#undef tan +#undef tanh +#undef fabsf +#undef fmodf +#undef modff +#undef rand +#undef srand +#undef errno +#undef getenv +#undef wcsspn +#undef open +#undef glob + +#undef wchar_t +#undef ptrdiff_t +#undef intptr_t +#undef uintptr_t +#undef timeval + + +#undef printf +#undef fprintf +#undef fwprintf +#undef vfprintf +#undef vfwprintf +#undef vprintf +#undef wprintf +#undef sprintf +#undef swprintf +#undef _snprintf +#if HAVE__SNWPRINTF +#undef _snwprintf +#endif /* HAVE__SNWPRINTF */ +#undef sscanf +#undef wcstod +#undef wcstol +#undef wcstoul +#undef _wcstoui64 +#undef wcscat +#undef wcscpy +#undef wcslen +#undef wcsncmp +#undef wcschr +#undef wcsrchr +#undef wsprintf +#undef swscanf +#undef wcspbrk +#undef wcsstr +#undef wcscmp +#undef wcsncat +#undef wcsncpy +#undef wcstok +#undef wcscspn +#undef iswupper +#undef iswspace +#undef towlower +#undef towupper +#undef vsprintf +#undef vswprintf +#undef _vsnprintf +#undef _vsnwprintf +#undef vsnprintf +#undef wvsnprintf + +#ifdef _AMD64_ +#undef _mm_getcsr +#undef _mm_setcsr +#endif // _AMD64_ + +#undef ctime + +#undef SCHAR_MIN +#undef SCHAR_MAX +#undef UCHAR_MAX +#undef SHRT_MIN +#undef SHRT_MAX +#undef USHRT_MAX +#undef LONG_MIN +#undef LONG_MAX +#undef ULONG_MAX +#undef RAND_MAX +#undef DBL_MAX +#undef FLT_MAX +#undef __record_type_class +#undef __real_type_class + +#if HAVE_CHAR_BIT +#undef CHAR_BIT +#endif + +// We need a sigsetjmp prototype in pal.h for the SEH macros, but we +// can't use the "real" prototype (because we don't want to define sigjmp_buf). +// So we must rename the "real" sigsetjmp to avoid redefinition errors. +#define sigsetjmp REAL_sigsetjmp +#define siglongjmp REAL_siglongjmp +#include <setjmp.h> +#undef sigsetjmp +#undef siglongjmp + +#undef _SIZE_T_DEFINED +#undef _WCHAR_T_DEFINED + +#define _DONT_USE_CTYPE_INLINE_ +#if HAVE_RUNETYPE_H +#include <runetype.h> +#endif +#include <ctype.h> + +// Don't use C++ wrappers for stdlib.h +// https://gcc.gnu.org/ml/libstdc++/2016-01/msg00025.html +#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS 1 + +#define _WITH_GETLINE +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <pwd.h> +#include <unistd.h> +#include <fcntl.h> +#include <glob.h> + +#ifdef __APPLE__ + +#undef GetCurrentThread +#include <CoreServices/CoreServices.h> + +#include <malloc/malloc.h> + +#endif // __APPLE__ + +/* we don't really need this header here, but by including it we make sure + we'll catch any definition conflicts */ +#include <sys/socket.h> + +#if !HAVE_INFTIM +#define INFTIM -1 +#endif // !HAVE_INFTIM + +#if (__GNUC__ >= 4) +#define OffsetOf(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) +#else +#define OffsetOf(s, f) (INT)(SIZE_T)&(((s*)0)->f) +#endif /* __GNUC__ version check*/ + +#undef assert +#define assert (Use__ASSERTE_instead_of_assert) assert + +#define PROCESS_PIPE_NAME_PREFIX ".dotnet-pal-processpipe" + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +typedef enum _TimeConversionConstants +{ + tccSecondsToMillieSeconds = 1000, // 10^3 + tccSecondsToMicroSeconds = 1000000, // 10^6 + tccSecondsToNanoSeconds = 1000000000, // 10^9 + tccMillieSecondsToMicroSeconds = 1000, // 10^3 + tccMillieSecondsToNanoSeconds = 1000000, // 10^6 + tccMicroSecondsToNanoSeconds = 1000, // 10^3 + tccSecondsTo100NanoSeconds = 10000000, // 10^7 + tccMicroSecondsTo100NanoSeconds = 10 // 10^1 +} TimeConversionConstants; + +#ifdef __cplusplus +} + +/* This is duplicated in utilcode.h for CLR, with cooler type-traits */ +template <typename T> +inline +T* InterlockedExchangePointerT( + T* volatile *Target, + T* Value) +{ + return (T*)(InterlockedExchangePointer( + (PVOID volatile*)Target, + (PVOID)Value)); +} + +template <typename T> +inline +T* InterlockedCompareExchangePointerT( + T* volatile *destination, + T* exchange, + T* comparand) +{ + return (T*)(InterlockedCompareExchangePointer( + (PVOID volatile*)destination, + (PVOID)exchange, + (PVOID)comparand)); +} + +template <typename T> +inline T* InterlockedExchangePointerT( + T* volatile * target, + int value) // When NULL is provided as argument. +{ + //STATIC_ASSERT(value == 0); + return InterlockedExchangePointerT(target, reinterpret_cast<T*>(value)); +} + +template <typename T> +inline T* InterlockedCompareExchangePointerT( + T* volatile * destination, + int exchange, // When NULL is provided as argument. + T* comparand) +{ + //STATIC_ASSERT(exchange == 0); + return InterlockedCompareExchangePointerT(destination, reinterpret_cast<T*>(exchange), comparand); +} + +template <typename T> +inline T* InterlockedCompareExchangePointerT( + T* volatile * destination, + T* exchange, + int comparand) // When NULL is provided as argument. +{ + //STATIC_ASSERT(comparand == 0); + return InterlockedCompareExchangePointerT(destination, exchange, reinterpret_cast<T*>(comparand)); +} + +#undef InterlockedExchangePointer +#define InterlockedExchangePointer InterlockedExchangePointerT +#undef InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointer InterlockedCompareExchangePointerT + +#include "volatile.h" + +const char StackOverflowMessage[] = "Process is terminated due to StackOverflowException.\n"; + +#endif // __cplusplus + +#endif /* _PAL_INTERNAL_H_ */ diff --git a/src/pal/src/include/pal/perftrace.h b/src/pal/src/include/pal/perftrace.h new file mode 100644 index 0000000000..fec46e2330 --- /dev/null +++ b/src/pal/src/include/pal/perftrace.h @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/perftrace.h + +Abstract: + Header file for PAL Performance trace utilities. + + + +--*/ + +/* +Overview of PAL Performance utilities + + */ + +#ifndef _PAL_PERFTRACE_H_ +#define _PAL_PERFTRACE_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +#if PAL_PERF +#define PERF_ENTRY(x) \ + ULONGLONG pal_perf_start_tick = 0;\ + PERFLogFunctionEntry( PAL_PERF_##x, &pal_perf_start_tick ) +#define PERF_EXIT(x) \ + PERFLogFunctionExit( PAL_PERF_##x, &pal_perf_start_tick ) +#define PERF_ENTRY_ONLY(x) \ + PERFNoLatencyProfileEntry( PAL_PERF_##x ) + +BOOL PERFInitialize(LPWSTR command_line, LPWSTR exe_path) ; +void PERFTerminate( ); +BOOL PERFAllocThreadInfo( ); +void PERFLogFunctionExit(unsigned int pal_api_id, ULONGLONG *pal_perf_start_tick); +void PERFLogFunctionEntry(unsigned int pal_api_id, ULONGLONG *pal_perf_start_tick); +void PERFEnableThreadProfile(BOOL isInternal); +void PERFDisableThreadProfile(BOOL isInternal); +void PERFEnableProcessProfile( ); +void PERFDisableProcessProfile( ); +BOOL PERFIsProcessProfileEnabled( ); +void PERFNoLatencyProfileEntry(unsigned int pal_api_id ); +void PERFCalibrate(const char* msg); + +#else /* PAL_PERF */ + +#define PERF_ENTRY(x) +#define PERF_ENTRY_ONLY(x) +#define PERF_EXIT(x) + +#endif /* PAL_PERF */ + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* _PAL_PERFTRACE_H_ */ + + + diff --git a/src/pal/src/include/pal/printfcpp.hpp b/src/pal/src/include/pal/printfcpp.hpp new file mode 100644 index 0000000000..0a728c9fd7 --- /dev/null +++ b/src/pal/src/include/pal/printfcpp.hpp @@ -0,0 +1,133 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + pal/printfcpp.hpp + +Abstract: + Declarations for suspension safe memory allocation functions + + + +--*/ + +#ifndef _PRINTFCPP_HPP +#define _PRINTFCPP_HPP + +#ifdef __cplusplus +#include "pal/threadinfo.hpp" +#endif + +#include <stdarg.h> + +#ifdef __cplusplus +typedef char16_t wchar_16; // __wchar_16_cpp (which is defined in palinternal.h) needs to be redefined to wchar_16. + +extern "C" +{ + int + __cdecl + PAL__vsnprintf( + LPSTR Buffer, + size_t Count, + LPCSTR Format, + va_list ap); + + int + __cdecl + PAL__wvsnprintf( + LPWSTR Buffer, + size_t Count, + LPCWSTR Format, + va_list ap); + + int + __cdecl + PAL_vfprintf( + PAL_FILE *stream, + const char *format, + va_list ap); + + int + __cdecl + PAL_vfwprintf( + PAL_FILE *stream, + const wchar_16 *format, + va_list ap); +} + +namespace CorUnix +{ + int + InternalVfprintf( + CPalThread *pthrCurrent, + PAL_FILE *stream, + const char *format, + va_list ap); + + int + InternalWvsnprintf( + CPalThread *pthrCurrent, + LPWSTR Buffer, + size_t Count, + LPCWSTR Format, + va_list ap); + + int + InternalVsnprintf( + CPalThread *pthrCurrent, + LPSTR Buffer, + size_t Count, + LPCSTR Format, + va_list ap); + + int + InternalVfwprintf( + CPalThread *pthrCurrent, + PAL_FILE *stream, + const wchar_16 *format, + va_list ap); + +} +#else // __cplusplus + + int + __cdecl + PAL__vsnprintf( + LPSTR Buffer, + size_t Count, + LPCSTR Format, + va_list ap); + + int + __cdecl + PAL__wvsnprintf( + LPWSTR Buffer, + size_t Count, + LPCWSTR Format, + va_list ap); + + int + __cdecl + PAL_vfprintf( + PAL_FILE *stream, + const char *format, + va_list ap); + + int + __cdecl + PAL_vfwprintf( + PAL_FILE *stream, + const wchar_16 *format, + va_list ap); + +#endif // __cplusplus + +#endif // _PRINTFCPP_HPP + diff --git a/src/pal/src/include/pal/process.h b/src/pal/src/include/pal/process.h new file mode 100644 index 0000000000..990aec5b21 --- /dev/null +++ b/src/pal/src/include/pal/process.h @@ -0,0 +1,162 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/process.h + +Abstract: + + Miscellaneous process related functions. + +Revision History: + + + +--*/ + +#ifndef _PAL_PROCESS_H_ +#define _PAL_PROCESS_H_ + +#include "pal/palinternal.h" + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/* thread ID of thread that has initiated an ExitProcess (or TerminateProcess). + this is to make sure only one thread cleans up the PAL, and also to prevent + calls to CreateThread from succeeding once shutdown has started + [defined in process.c] +*/ +extern Volatile<LONG> terminator; + +// The process and session ID of this process, so we can avoid excessive calls to getpid() and getsid(). +extern DWORD gPID; +extern DWORD gSID; + +extern LPWSTR pAppDir; + +/*++ +Function: + PROCGetProcessIDFromHandle + +Abstract + Return the process ID from a process handle +--*/ +DWORD PROCGetProcessIDFromHandle(HANDLE hProcess); + +/*++ +Function: + PROCCreateInitialProcess + +Abstract + Initialize all the structures for the initial process. + +Parameter + lpwstrCmdLine: Command line. + lpwstrFullPath : Full path to executable + +Return + TRUE: if successful + FALSE: otherwise + +Notes : + This function takes ownership of lpwstrCmdLine, but not of lpwstrFullPath +--*/ +BOOL PROCCreateInitialProcess(LPWSTR lpwstrCmdLine, LPWSTR lpwstrFullPath); + +/*++ +Function: + PROCCleanupInitialProcess + +Abstract + Cleanup all the structures for the initial process. + +Parameter + VOID + +Return + VOID + +--*/ +VOID PROCCleanupInitialProcess(VOID); + +#if USE_SYSV_SEMAPHORES +/*++ +Function: + PROCCleanupThreadSemIds(VOID); + +Abstract + Cleanup SysV semaphore ids for all threads. + +(no parameters, no return value) +--*/ +VOID PROCCleanupThreadSemIds(VOID); +#endif + +/*++ +Function: + PROCProcessLock + +Abstract + Enter the critical section associated to the current process +--*/ +VOID PROCProcessLock(VOID); + + +/*++ +Function: + PROCProcessUnlock + +Abstract + Leave the critical section associated to the current process +--*/ +VOID PROCProcessUnlock(VOID); + +/*++ +Function: + PROCAbort() + + Aborts the process after calling the shutdown cleanup handler. This function + should be called instead of calling abort() directly. + + Does not return +--*/ +PAL_NORETURN +void PROCAbort(); + +/*++ +Function: + PROCNotifyProcessShutdown + + Calls the abort handler to do any shutdown cleanup. Call be + called from the unhandled native exception handler. + +(no return value) +--*/ +void PROCNotifyProcessShutdown(); + +/*++ +Function: + InitializeFlushProcessWriteBuffers + +Abstract + This function initializes data structures needed for the FlushProcessWriteBuffers +Return + TRUE if it succeeded, FALSE otherwise +--*/ +BOOL InitializeFlushProcessWriteBuffers(); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif //PAL_PROCESS_H_ + diff --git a/src/pal/src/include/pal/procobj.hpp b/src/pal/src/include/pal/procobj.hpp new file mode 100644 index 0000000000..a75c764246 --- /dev/null +++ b/src/pal/src/include/pal/procobj.hpp @@ -0,0 +1,125 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/procobj.hpp + +Abstract: + Header file for process structures + + + +--*/ + +#ifndef _PAL_PROCOBJ_HPP_ +#define _PAL_PROCOBJ_HPP_ + +#include "corunix.hpp" + +namespace CorUnix +{ + extern CObjectType otProcess; + + typedef enum + { + PS_IDLE, + PS_STARTING, + PS_RUNNING, + PS_DONE + } PROCESS_STATE; + + // + // Struct for process module list (EnumProcessModules) + // + struct ProcessModules + { + ProcessModules *Next; + PVOID BaseAddress; + CHAR Name[0]; + }; + + // + // Ideally dwProcessId would be part of the process object's immutable + // data. Doing so, though, creates complications in CreateProcess. The + // contents of the immutable data for a new object must be set before + // that object is registered with the object manager (as the object + // manager may make a copy of the immutable data). The PID for a new + // process, though, is not known until after creation. Registering the + // process object after process creation creates an undesirable error path + // -- if we are not able to register the process object (say, because of + // a low resource condition) we would be forced to return an error to + // the caller of CreateProcess, even though the new process was actually + // created... + // + // Note: we could work around this by effectively always going down + // the create suspended path. That is, the new process would not exec until + // the parent process released it. It's unclear how much benefit this would + // provide us. + // + + class CProcProcessLocalData + { + public: + CProcProcessLocalData() + : + dwProcessId(0), + ps(PS_IDLE), + dwExitCode(0), + lAttachCount(0), + pProcessModules(NULL), + cProcessModules(0) + { + }; + + ~CProcProcessLocalData(); + + DWORD dwProcessId; + PROCESS_STATE ps; + DWORD dwExitCode; + LONG lAttachCount; + ProcessModules *pProcessModules; + DWORD cProcessModules; + }; + + PAL_ERROR + InternalCreateProcess( + CPalThread *pThread, + LPCWSTR lpApplicationName, + LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation + ); + + PAL_ERROR + InitializeProcessData( + void + ); + + PAL_ERROR + InitializeProcessCommandLine( + LPWSTR lpwstrCmdLine, + LPWSTR lpwstrFullPath + ); + + PAL_ERROR + CreateInitialProcessAndThreadObjects( + CPalThread *pThread + ); + + extern IPalObject *g_pobjProcess; +} + +#endif // _PAL_PROCOBJ_HPP_ + diff --git a/src/pal/src/include/pal/seh.hpp b/src/pal/src/include/pal/seh.hpp new file mode 100644 index 0000000000..3ac93d655a --- /dev/null +++ b/src/pal/src/include/pal/seh.hpp @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/seh.hpp + +Abstract: + Header file for public Structured Exception Handling stuff + + + +--*/ + +#ifndef _PAL_SEH_HPP_ +#define _PAL_SEH_HPP_ + +#include "config.h" +#include "pal/palinternal.h" +#include "pal/corunix.hpp" + +// Uncomment this define to turn off the signal handling thread. +// #define DO_NOT_USE_SIGNAL_HANDLING_THREAD + +/*++ +Function : + SEHInitialize + + Initialize all SEH-related stuff (signals, etc) + +Parameters: + CPalThread * pthrCurrent : reference to the current thread. + flags : PAL initialize flags + +Return value: + TRUE if SEH support initialization succeeded, + FALSE otherwise + +--*/ +BOOL +SEHInitialize(CorUnix::CPalThread *pthrCurrent, DWORD flags); + +/*++ +Function : + SEHCleanup + + Clean up SEH-related stuff(signals, etc) + +Parameters: + None + + (no return value) +--*/ +VOID +SEHCleanup(); + +/*++ +Function: + SEHProcessException + + Send the PAL exception to any handler registered. + +Parameters: + PAL_SEHException* exception + +Return value: + Returns TRUE if the exception happened in managed code and the execution should + continue (with possibly modified context). + Returns FALSE if the exception happened in managed code and it was not handled. + In case the exception was handled by calling a catch handler, it doesn't return at all. +--*/ +BOOL +SEHProcessException(PAL_SEHException* exception); + +/*++ +Function: + AllocateExceptionRecords + +Parameters: + exceptionRecord - output pointer to the allocated Windows exception record + contextRecord - output pointer to the allocated Windows context record +--*/ +VOID +AllocateExceptionRecords(EXCEPTION_RECORD** exceptionRecord, CONTEXT** contextRecord); + +#if !HAVE_MACH_EXCEPTIONS +// TODO: Implement for Mach exceptions. Not in CoreCLR surface area. +/*++ +Function : + SEHHandleControlEvent + + handle Control-C and Control-Break events (call handler routines, + notify debugger) + +Parameters : + DWORD event : event that occurred + LPVOID eip : instruction pointer when exception occurred + +(no return value) + +Notes : + Handlers are called on a last-installed, first called basis, until a + handler returns TRUE. If no handler returns TRUE (or no hanlder is + installed), the default behavior is to call ExitProcess +--*/ +void SEHHandleControlEvent(DWORD event, LPVOID eip); +#endif // !HAVE_MACH_EXCEPTIONS + +#if !HAVE_MACH_EXCEPTIONS +/*++ +Function : + SEHSetSafeState + + specify whether the current thread is in a state where exception handling + of signals can be done safely + +Parameters: + CPalThread * pthrCurrent : reference to the current thread. + BOOL state : TRUE if the thread is safe, FALSE otherwise + +(no return value) +--*/ +void SEHSetSafeState(CorUnix::CPalThread *pthrCurrent, BOOL state); + +/*++ +Function : + SEHGetSafeState + + determine whether the current thread is in a state where exception handling + of signals can be done safely + +Parameters: + CPalThread * pthrCurrent : reference to the current thread. + +Return value : + TRUE if the thread is in a safe state, FALSE otherwise +--*/ +BOOL SEHGetSafeState(CorUnix::CPalThread *pthrCurrent); +#endif // !HAVE_MACH_EXCEPTIONS + +extern "C" +{ + +#ifdef FEATURE_PAL_SXS +/*++ +Function : + SEHEnable + + Enable SEH-related stuff on this thread + +Parameters: + CPalThread * pthrCurrent : reference to the current thread. + +Return value : + ERROR_SUCCESS, if enabling succeeded + an error code, otherwise +--*/ +CorUnix::PAL_ERROR SEHEnable(CorUnix::CPalThread *pthrCurrent); + +/*++ +Function : + SEHDisable + + Disable SEH-related stuff on this thread + +Parameters: + CPalThread * pthrCurrent : reference to the current thread. + +Return value : + ERROR_SUCCESS, if enabling succeeded + an error code, otherwise +--*/ +CorUnix::PAL_ERROR SEHDisable(CorUnix::CPalThread *pthrCurrent); + +#endif // FEATURE_PAL_SXS + +} + +#endif /* _PAL_SEH_HPP_ */ + diff --git a/src/pal/src/include/pal/semaphore.hpp b/src/pal/src/include/pal/semaphore.hpp new file mode 100644 index 0000000000..2943d61c3d --- /dev/null +++ b/src/pal/src/include/pal/semaphore.hpp @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + semaphore.hpp + +Abstract: + + Semaphore object structure definition. + + + +--*/ + +#ifndef _PAL_SEMAPHORE_H_ +#define _PAL_SEMAPHORE_H_ + +#include "corunix.hpp" + +namespace CorUnix +{ + extern CObjectType otSemaphore; + + typedef struct + { + LONG lMaximumCount; + } SemaphoreImmutableData; + + PAL_ERROR + InternalCreateSemaphore( + CPalThread *pThread, + LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, + LONG lInitialCount, + LONG lMaximumCount, + LPCWSTR lpName, + HANDLE *phSemaphore + ); + + PAL_ERROR + InternalReleaseSemaphore( + CPalThread *pThread, + HANDLE hSemaphore, + LONG lReleaseCount, + LPLONG lpPreviousCount + ); + + PAL_ERROR + InternalOpenSemaphore( + CPalThread *pThread, + DWORD dwDesiredAccess, + BOOL bInheritHandle, + LPCWSTR lpName, + HANDLE *phSemaphore + ); + +} + +#endif //_PAL_SEMAPHORE_H_ + + + + + + + + + + diff --git a/src/pal/src/include/pal/sharedmemory.h b/src/pal/src/include/pal/sharedmemory.h new file mode 100644 index 0000000000..45cc4b2c8d --- /dev/null +++ b/src/pal/src/include/pal/sharedmemory.h @@ -0,0 +1,268 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#ifndef _PAL_SHARED_MEMORY_H_ +#define _PAL_SHARED_MEMORY_H_ + +#include "corunix.hpp" + +#ifndef static_assert_no_msg +#define static_assert_no_msg( cond ) static_assert( cond, #cond ) +#endif // !static_assert_no_msg + +#ifndef _countof +#define _countof(a) (sizeof(a) / sizeof(a[0])) +#endif // !_countof + +// - Global shared memory files go in: +// /tmp/.dotnet/shm/global/<fileName> +// - Session-scoped shared memory files go in: +// /tmp/.dotnet/shm/session<sessionId>/<fileName> +// - Lock files associated with global shared memory files go in: +// /tmp/.dotnet/lockfiles/global/<fileName> +// - Lock files associated with session-scoped shared memory files go in: +// /tmp/.dotnet/lockfiles/session<sessionId>/<fileName> + +#define SHARED_MEMORY_MAX_FILE_NAME_CHAR_COUNT (_MAX_FNAME - 1) +#define SHARED_MEMORY_MAX_NAME_CHAR_COUNT (_countof("Global\\") - 1 + SHARED_MEMORY_MAX_FILE_NAME_CHAR_COUNT) + +#define SHARED_MEMORY_TEMP_DIRECTORY_PATH "/tmp" +#define SHARED_MEMORY_RUNTIME_TEMP_DIRECTORY_PATH "/tmp/.dotnet" + +#define SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH "/tmp/.dotnet/shm" +#define SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH "/tmp/.dotnet/lockfiles" +static_assert_no_msg(_countof(SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH) >= _countof(SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH)); + +#define SHARED_MEMORY_GLOBAL_DIRECTORY_NAME "global" +#define SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX "session" +static_assert_no_msg(_countof(SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX) >= _countof(SHARED_MEMORY_GLOBAL_DIRECTORY_NAME)); + +#define SHARED_MEMORY_UNIQUE_TEMP_NAME_TEMPLATE "/tmp/.coreclr.XXXXXX" + +#define SHARED_MEMORY_MAX_SESSION_ID_CHAR_COUNT (10) + +#define SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT \ + ( \ + _countof(SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH) - 1 + \ + 1 /* path separator */ + \ + _countof(SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX) - 1 + \ + SHARED_MEMORY_MAX_SESSION_ID_CHAR_COUNT + \ + 1 /* path separator */ + \ + SHARED_MEMORY_MAX_FILE_NAME_CHAR_COUNT \ + ) +static_assert_no_msg(SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1 /* null terminator */ <= MAX_LONGPATH); + +class AutoFreeBuffer +{ +private: + void *m_buffer; + bool m_cancel; + +public: + AutoFreeBuffer(void *buffer); + ~AutoFreeBuffer(); + +public: + void Cancel(); +}; + +enum class SharedMemoryError : DWORD +{ + NameEmpty = ERROR_INVALID_PARAMETER, + NameTooLong = ERROR_FILENAME_EXCED_RANGE, + NameInvalid = ERROR_INVALID_NAME, + HeaderMismatch = ERROR_INVALID_HANDLE, + OutOfMemory = ERROR_NOT_ENOUGH_MEMORY, + IO = ERROR_OPEN_FAILED +}; + +class SharedMemoryException +{ +private: + DWORD m_errorCode; + +public: + SharedMemoryException(DWORD errorCode); + DWORD GetErrorCode() const; +}; + +class SharedMemoryHelpers +{ +private: + static const mode_t PermissionsMask_AllUsers_ReadWrite; + static const mode_t PermissionsMask_AllUsers_ReadWriteExecute; +public: + static const UINT32 InvalidProcessId; + static const SIZE_T InvalidThreadId; + static const UINT64 InvalidSharedThreadId; + +public: + static SIZE_T AlignDown(SIZE_T value, SIZE_T alignment); + static SIZE_T AlignUp(SIZE_T value, SIZE_T alignment); + + static void *Alloc(SIZE_T byteCount); + + template<SIZE_T DestinationByteCount, SIZE_T SourceByteCount> static SIZE_T CopyString(char (&destination)[DestinationByteCount], SIZE_T destinationStartOffset, const char (&source)[SourceByteCount]); + template<SIZE_T DestinationByteCount> static SIZE_T CopyString(char (&destination)[DestinationByteCount], SIZE_T destinationStartOffset, LPCSTR source, SIZE_T sourceCharCount); + template<SIZE_T DestinationByteCount> static SIZE_T AppendUInt32String(char (&destination)[DestinationByteCount], SIZE_T destinationStartOffset, UINT32 value); + + static bool EnsureDirectoryExists(const char *path, bool isGlobalLockAcquired, bool createIfNotExist = true); +private: + static int Open(LPCSTR path, int flags, mode_t mode = static_cast<mode_t>(0)); +public: + static int OpenDirectory(LPCSTR path); + static int CreateOrOpenFile(LPCSTR path, bool createIfNotExist = true, bool *createdRef = nullptr); + static void CloseFile(int fileDescriptor); + + static SIZE_T GetFileSize(int fileDescriptor); + static void SetFileSize(int fileDescriptor, SIZE_T byteCount); + + static void *MemoryMapFile(int fileDescriptor, SIZE_T byteCount); + + static bool TryAcquireFileLock(int fileDescriptor, int operation); + static void ReleaseFileLock(int fileDescriptor); +}; + +class SharedMemoryId +{ +private: + LPCSTR m_name; + SIZE_T m_nameCharCount; + bool m_isSessionScope; // false indicates global scope + +public: + SharedMemoryId(); + SharedMemoryId(LPCSTR name, SIZE_T nameCharCount, bool isSessionScope); + SharedMemoryId(LPCSTR name); + +public: + LPCSTR GetName() const; + SIZE_T GetNameCharCount() const; + bool IsSessionScope() const; + bool Equals(SharedMemoryId *other) const; + +public: + SIZE_T AppendSessionDirectoryName(char (&path)[SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1], SIZE_T pathCharCount) const; +}; + +enum class SharedMemoryType : UINT8 +{ + Mutex +}; + +class SharedMemorySharedDataHeader +{ +private: + union + { + struct + { + SharedMemoryType m_type; + UINT8 m_version; + }; + UINT64 _raw; // use the same size for the header on all archs, and align the data to a pointer + }; + +public: + static SIZE_T DetermineTotalByteCount(SIZE_T dataByteCount); + +public: + SharedMemorySharedDataHeader(SharedMemoryType type, UINT8 version); + +public: + SharedMemoryType GetType() const; + UINT8 GetVersion() const; + void *GetData(); +}; + +class SharedMemoryProcessDataBase +{ +public: + virtual void Close(bool isAbruptShutdown, bool releaseSharedData) + { + } + + virtual ~SharedMemoryProcessDataBase() + { + } +}; + +class SharedMemoryProcessDataHeader +{ +private: + SIZE_T m_refCount; + SharedMemoryId m_id; + SharedMemoryProcessDataBase *m_data; + int m_fileDescriptor; + SharedMemorySharedDataHeader *m_sharedDataHeader; + SIZE_T m_sharedDataTotalByteCount; + SharedMemoryProcessDataHeader *m_nextInProcessDataHeaderList; + +public: + static SharedMemoryProcessDataHeader *CreateOrOpen(LPCSTR name, SharedMemorySharedDataHeader requiredSharedDataHeader, SIZE_T sharedDataByteCount, bool createIfNotExist, bool *createdRef); + +public: + static SharedMemoryProcessDataHeader *PalObject_GetProcessDataHeader(CorUnix::IPalObject *object); + static void PalObject_SetProcessDataHeader(CorUnix::IPalObject *object, SharedMemoryProcessDataHeader *processDataHeader); + static void PalObject_Close(CorUnix::CPalThread *thread, CorUnix::IPalObject *object, bool isShuttingDown, bool cleanUpPalSharedState); + +private: + SharedMemoryProcessDataHeader(SharedMemoryId *id, int fileDescriptor, SharedMemorySharedDataHeader *sharedDataHeader, SIZE_T sharedDataTotalByteCount); +public: + static SharedMemoryProcessDataHeader *New(SharedMemoryId *id, int fileDescriptor, SharedMemorySharedDataHeader *sharedDataHeader, SIZE_T sharedDataTotalByteCount); + ~SharedMemoryProcessDataHeader(); + void Close(); + +public: + SharedMemoryId *GetId(); + SharedMemoryProcessDataBase *GetData() const; + void SetData(SharedMemoryProcessDataBase *data); + SharedMemorySharedDataHeader *GetSharedDataHeader() const; + SIZE_T GetSharedDataTotalByteCount() const; + SharedMemoryProcessDataHeader *GetNextInProcessDataHeaderList() const; + void SetNextInProcessDataHeaderList(SharedMemoryProcessDataHeader *next); + +public: + void IncRefCount(); + void DecRefCount(); +}; + +class SharedMemoryManager +{ +private: + static CRITICAL_SECTION s_creationDeletionProcessLock; + static int s_creationDeletionLockFileDescriptor; + +private: + static SharedMemoryProcessDataHeader *s_processDataHeaderListHead; + +#ifdef _DEBUG +private: + static SIZE_T s_creationDeletionProcessLockOwnerThreadId; + static SIZE_T s_creationDeletionFileLockOwnerThreadId; +#endif // _DEBUG + +public: + static void StaticInitialize(); + static void StaticClose(); + +public: + static void AcquireCreationDeletionProcessLock(); + static void ReleaseCreationDeletionProcessLock(); + static void AcquireCreationDeletionFileLock(); + static void ReleaseCreationDeletionFileLock(); + +#ifdef _DEBUG +public: + static bool IsCreationDeletionProcessLockAcquired(); + static bool IsCreationDeletionFileLockAcquired(); +#endif // _DEBUG + +public: + static void AddProcessDataHeader(SharedMemoryProcessDataHeader *processDataHeader); + static void RemoveProcessDataHeader(SharedMemoryProcessDataHeader *processDataHeader); + static SharedMemoryProcessDataHeader *FindProcessDataHeader(SharedMemoryId *id); +}; + +#endif // !_PAL_SHARED_MEMORY_H_ diff --git a/src/pal/src/include/pal/sharedmemory.inl b/src/pal/src/include/pal/sharedmemory.inl new file mode 100644 index 0000000000..69b8704b65 --- /dev/null +++ b/src/pal/src/include/pal/sharedmemory.inl @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#ifndef _PAL_SHARED_MEMORY_INL_ +#define _PAL_SHARED_MEMORY_INL_ + +#include "sharedmemory.h" + +#include "dbgmsg.h" + +#include <string.h> + +template<SIZE_T DestinationByteCount, SIZE_T SourceByteCount> +SIZE_T SharedMemoryHelpers::CopyString( + char (&destination)[DestinationByteCount], + SIZE_T destinationStartOffset, + const char(&source)[SourceByteCount]) +{ + return CopyString(destination, destinationStartOffset, source, SourceByteCount - 1); +} + +template<SIZE_T DestinationByteCount> +SIZE_T SharedMemoryHelpers::CopyString( + char (&destination)[DestinationByteCount], + SIZE_T destinationStartOffset, + LPCSTR source, + SIZE_T sourceCharCount) +{ + _ASSERTE(destinationStartOffset < DestinationByteCount); + _ASSERTE(sourceCharCount < DestinationByteCount - destinationStartOffset); + _ASSERTE(strlen(source) == sourceCharCount); + + memcpy_s(&destination[destinationStartOffset], DestinationByteCount - destinationStartOffset, source, sourceCharCount + 1); + return destinationStartOffset + sourceCharCount; +} + +template<SIZE_T DestinationByteCount> +SIZE_T SharedMemoryHelpers::AppendUInt32String( + char (&destination)[DestinationByteCount], + SIZE_T destinationStartOffset, + UINT32 value) +{ + _ASSERTE(destination != nullptr); + _ASSERTE(destinationStartOffset < DestinationByteCount); + + int valueCharCount = + sprintf_s(&destination[destinationStartOffset], DestinationByteCount - destinationStartOffset, "%u", value); + _ASSERTE(valueCharCount > 0); + return destinationStartOffset + valueCharCount; +} + +#endif // !_PAL_SHARED_MEMORY_INL_ diff --git a/src/pal/src/include/pal/shm.hpp b/src/pal/src/include/pal/shm.hpp new file mode 100644 index 0000000000..de1d09e636 --- /dev/null +++ b/src/pal/src/include/pal/shm.hpp @@ -0,0 +1,83 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/shm.hpp + +Abstract: + C++ typesafe accessors for shared memory routines + + + +--*/ + +#ifndef _SHM_HPP_ +#define _SHM_HPP_ + +#include "shmemory.h" + +// +// Some compilers (e.g., HPUX/IA64) warn about using NULL to initialize +// something of type SHMPTR, since SHMPTR is defined as DWORD_PTR, which +// isn't considered a pointer type... +// + +#define SHMNULL 0 + +#ifndef _DEBUG + +inline +void * +ShmPtrToPtrFast(SHMPTR shmptr) +{ + void *pv = NULL; + + if (SHMNULL != shmptr) + { + int segment = shmptr >> 24; + + if (segment < shm_numsegments) + { + pv = reinterpret_cast<void*>( + reinterpret_cast<DWORD_PTR>(shm_segment_bases[(uint)segment].Load()) + + (shmptr & 0x00FFFFFF) + ); + } + else + { + pv = SHMPtrToPtr(shmptr); + } + } + + return pv; +} + +// +// We could use a function template here to avoid the cast / macro +// + +#define SHMPTR_TO_TYPED_PTR(type, shmptr) reinterpret_cast<type*>(ShmPtrToPtrFast((shmptr))) + +#else + +#define SHMPTR_TO_TYPED_PTR(type, shmptr) reinterpret_cast<type*>(SHMPtrToPtr((shmptr))) + +#endif + +/* Set ptr to NULL if shmPtr == 0, else set ptr to SHMPTR_TO_TYPED_PTR(type, shmptr) + return FALSE if SHMPTR_TO_TYPED_PTR returns NULL ptr from non null shmptr, + TRUE otherwise */ +#define SHMPTR_TO_TYPED_PTR_BOOL(type, ptr, shmptr) \ + ((shmptr != 0) ? ((ptr = SHMPTR_TO_TYPED_PTR(type, shmptr)) != NULL) : ((ptr = NULL) == NULL)) + + + + +#endif // _SHM_HPP_ + diff --git a/src/pal/src/include/pal/shmemory.h b/src/pal/src/include/pal/shmemory.h new file mode 100644 index 0000000000..5ca848148c --- /dev/null +++ b/src/pal/src/include/pal/shmemory.h @@ -0,0 +1,331 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/shmemory.h + +Abstract: + Header file for interface to shared memory + +How to use : + +The SHMalloc function can be used to allocate memory in the shared memory area. +It returns a value of type SHMPTR, which will be useable in all participating +processes. The SHMPTR_TO_PTR macro can be used to convert a SHMPTR value into +an address valid *only* within the current process. Do NOT store pointers in +shared memory, since those will not be valid for other processes. If you need +to construct linked lists or other strctures that usually use pointers, use +SHMPTR values instead of pointers. In addition, Lock/Release functions must be +used when manipulating data in shared memory, to ensure inter-process synchronization. + +Example : + +//a simple linked list type +typedef struct +{ +int count; +SHMPTR string; +SHMPTR next; +}SHMLIST; + +// Allocate a new list item +SHMPTR new_item = SHMalloc(sizeof(SHMLIST)); + +// get a pointer to it +SHMLIST *item_ptr = (SHMLIST *)SHMPTR_TO_PTR(new_item); + +// Allocate memory for the "string" member, initialize it +item_ptr->string = SHMalloc(strlen("string")); +LPSTR str_ptr = (LPSTR)SHMPTR_TO_PTR(item_ptr->string); +strcpy(str_ptr, "string"); + +//Take the shared memory lock to prevent anyone from modifying the linked list +SHMLock(); + +//get the list's head from somewhere +SHMPTR list_head = get_list_head(); + +//link the list to our new item +item_ptr->next = list_head + +//get a pointer to the list head's structure +SHMLIST *head_ptr = (SHMLIST *)SHMPTR_TO_PTR(list_head); + +//set the new item's count value based on the head's count value +item_ptr->count = head_ptr->count + 1; + +//save the new item as the new head of the list +set_list_head(new_item); + +//We're done modifying the list, release the lock +SHMRelease + + + +--*/ + +#ifndef _PAL_SHMEMORY_H_ +#define _PAL_SHMEMORY_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/* +Type for shared memory blocks. use SHMPTR_TO_PTR to get a useable address. + */ +typedef DWORD_PTR SHMPTR; + +#define MAX_SEGMENTS 256 + + +typedef enum { + SIID_PROCESS_INFO,/* pointers to PROCESS structures? */ + SIID_NAMED_OBJECTS, + SIID_FILE_LOCKS, + + SIID_LAST +} SHM_INFO_ID; + +typedef enum +{ + SHM_NAMED_MAPPINGS, /* structs with map name, file name & flags? */ + SHM_NAMED_EVENTS, /* structs with event names & ThreadWaitingList struct? */ + SHM_NAMED_MUTEXS, /* structs with mutext names, and ThreadWaitingList struct */ + + SHM_NAMED_LAST +} SHM_NAMED_OBJECTS_ID; + +typedef struct _SMNO +{ + SHM_NAMED_OBJECTS_ID ObjectType; + SHMPTR ShmNext; + SHMPTR ShmObjectName; + SHMPTR ShmSelf; + +}SHM_NAMED_OBJECTS, * PSHM_NAMED_OBJECTS; + + +/* +SHMPTR_TO_PTR + +Macro to convert a SHMPTR value into a valid (for this process) pointer. + +In debug builds, we always call the function to do full checks. +In release builds, check if the segment is known, and if it is, do only minimal +validation (if segment is unknown, we have to call the function) + */ +#if _DEBUG + +#define SHMPTR_TO_PTR(shmptr) \ + SHMPtrToPtr(shmptr) + +#else /* !_DEBUG */ + +extern int shm_numsegments; + +/* array containing the base address of each segment */ +extern Volatile<LPVOID> shm_segment_bases[MAX_SEGMENTS]; + +#define SHMPTR_TO_PTR(shmptr)\ + ((shmptr)?(((static_cast<int>(shmptr)>>24)<shm_numsegments)?\ + reinterpret_cast<LPVOID>(reinterpret_cast<size_t>(shm_segment_bases[static_cast<int>(shmptr)>>24].Load())+(static_cast<int>(shmptr)&0x00FFFFFF)):\ + SHMPtrToPtr(shmptr)): static_cast<LPVOID>(NULL)) + + +#endif /* _DEBUG */ + +/* Set ptr to NULL if shmPtr == 0, else set ptr to SHMPTR_TO_PTR(shmptr) + return FALSE if SHMPTR_TO_PTR returns NULL ptr from non null shmptr, + TRUE otherwise */ +#define SHMPTR_TO_PTR_BOOL(ptr, shmptr) \ + ((shmptr != 0) ? ((ptr = SHMPTR_TO_PTR(shmptr)) != NULL) : ((ptr = NULL) == NULL)) + +/*++ +SHMPtrToPtr + +Convert a SHMPTR value into a useable pointer. + +Unlike the macro defined above, this function performs as much validation as +possible, and can handle cases when the SHMPTR is located in an aread of shared +memory the process doesn't yet know about. +--*/ +LPVOID SHMPtrToPtr(SHMPTR shmptr); + +/*++ +SHMInitialize + +Hook this process into the PAL shared memory system; initialize the shared +memory if no other process has done it. +--*/ +BOOL SHMInitialize(void); + +/*++ +SHMCleanup + +Release all shared memory resources held; remove ourselves from the list of +registered processes, and remove all shared memory files if no process remains +--*/ +void SHMCleanup(void); + +/*++ +SHMalloc + +Allocate a block of memory of the specified size + +Parameters : + size_t size : size of block required + +Return value : + A SHMPTR identifying the new block, or 0 on failure. Use SHMPtrToPtr to + convert a SHMPTR into a useable pointer (but remember to lock the shared + memory first!) + +Notes : + SHMalloc will fail if the requested size is larger than a certain maximum. + At the moment, the maximum is 520 bytes (MAX_PATH_FNAME*2). +--*/ +SHMPTR SHMalloc(size_t size); + +/*++ +SHMfree + +Release a block of shared memory and put it back in the shared memory pool + +Parameters : + SHMPTR shmptr : identifier of block to release + +(no return value) +--*/ +void SHMfree(SHMPTR shmptr); + +/*++ +SHMLock + +Restrict shared memory access to the current thread of the current process + +(no parameters) + +Return value : + New lock count +--*/ +int SHMLock(void); + +/*++ +SHMRelease + +Release a lock on shared memory taken with SHMLock. + +(no parameters) + +Return value : + New lock count +--*/ +int SHMRelease(void); + + +/*++ +Function : + SHMGetInfo + + Retrieve some information from shared memory + +Parameters : + SHM_INFO_ID element : identifier of element to retrieve + +Return value : + Value of specified element + +Notes : + The SHM lock should be held while manipulating shared memory +--*/ +SHMPTR SHMGetInfo(SHM_INFO_ID element); + +/*++ +Function : + SHMSetInfo + + Place some information into shared memory + +Parameters : + SHM_INFO_ID element : identifier of element to save + SHMPTR value : new value of element + +Return value : + TRUE if successfull, FALSE otherwise. + +Notes : + The SHM lock should be held while manipulating shared memory +--*/ +BOOL SHMSetInfo(SHM_INFO_ID element, SHMPTR value); + + +/********************** Shared memory help functions ********************/ + +/*++ +SHMStrDup + +Duplicates the string in shared memory. + +Returns the new address as SHMPTR on success. +Returns (SHMPTR)NULL on failure. +--*/ +SHMPTR SHMStrDup( LPCSTR string ); + +/*++ +SHMWStrDup + +Duplicates the wide string in shared memory. + +Returns the new address as SHMPTR on success. +Returns (SHMPTR)NULL on failure. +--*/ +SHMPTR SHMWStrDup( LPCWSTR string ); + + +/*++ +SHMFindNamedObjectByName + +Searches for an object whose name matches the name and ID passed in. + +Returns a SHMPTR to its location in shared memory. If no object +matches the name, the function returns NULL and sets pbNameExists to FALSE. +If an object matches the name but is of a different type, the function +returns NULL and sets pbNameExists to TRUE. + +--*/ +SHMPTR SHMFindNamedObjectByName( LPCWSTR lpName, SHM_NAMED_OBJECTS_ID oid, + BOOL *pbNameExists ); + +/*++ +SHMRemoveNamedObject + +Removes the specified named object from the list + +No return. + +note : the caller is reponsible for releasing all associated memory +--*/ +void SHMRemoveNamedObject( SHMPTR shmNamedObject ); + +/*++ SHMAddNamedObject + +Adds the specified named object to the list. + +No return. +--*/ +void SHMAddNamedObject( SHMPTR shmNewNamedObject ); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* _PAL_SHMEMORY_H_ */ + diff --git a/src/pal/src/include/pal/stackstring.hpp b/src/pal/src/include/pal/stackstring.hpp new file mode 100644 index 0000000000..1f18d5fe03 --- /dev/null +++ b/src/pal/src/include/pal/stackstring.hpp @@ -0,0 +1,239 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#ifndef __STACKSTRING_H_ +#define __STACKSTRING_H_ + +template <SIZE_T STACKCOUNT, class T> +class StackString +{ +private: + T m_innerBuffer[STACKCOUNT + 1]; + T * m_buffer; + SIZE_T m_size; // actual allocated size + SIZE_T m_count; // actual length of string + + void NullTerminate() + { + m_buffer[m_count] = 0; + } + + void DeleteBuffer() + { + if (m_innerBuffer != m_buffer) + PAL_free(m_buffer); + + m_buffer = NULL; + return; + } + + BOOL ReallocateBuffer(SIZE_T count) + { + // count is always > STACKCOUNT here. + // We got so far, we will allocate a little extra + // to prevent frequent allocations +#if _DEBUG + SIZE_T count_allocated = count; +#else + SIZE_T count_allocated = count + 100; +#endif //_DEBUG + + BOOL dataOnStack = m_buffer == m_innerBuffer; + if( dataOnStack ) + { + m_buffer = NULL; + } + + T * newBuffer = (T *)PAL_realloc(m_buffer, (count_allocated + 1) * sizeof(T)); + if (NULL == newBuffer) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + + DeleteBuffer(); + m_count = 0; + m_buffer = m_innerBuffer; + return FALSE; + } + + if( dataOnStack) + { + CopyMemory(newBuffer, m_innerBuffer, (m_count + 1) * sizeof(T)); + } + + m_buffer = newBuffer; + m_count = count; + m_size = count_allocated + 1; + + return TRUE; + } + + BOOL HasAvailableMemory(SIZE_T count) + { + return (count < m_size); + } + + //NOTE: Always call this before modifying the underlying buffer + BOOL Resize(SIZE_T count) + { + + if (NULL == m_buffer) + { + m_buffer = m_innerBuffer; + } + + if (HasAvailableMemory(count)) + { + m_count = count; + } + else + { + if (count > STACKCOUNT) + { + return ReallocateBuffer(count); + } + else + { + m_count = count; + m_size = STACKCOUNT+1; + } + } + + return TRUE; + } + + StackString(const StackString &s) + { + Set(s); + } + +public: + StackString() + : m_buffer(m_innerBuffer), m_size(0), m_count(0) + { + } + + + BOOL Set(const T * buffer, SIZE_T count) + { + if (!Resize(count)) + return FALSE; + + CopyMemory(m_buffer, buffer, (count + 1) * sizeof(T)); + NullTerminate(); + return TRUE; + } + + BOOL Set(const StackString &s) + { + return Set(s.m_buffer, s.m_count); + } + + SIZE_T GetCount() const + { + return m_count; + } + + SIZE_T GetSizeOf() const + { + return m_size * sizeof(T); + } + + CONST T * GetString() const + { + return (const T *)m_buffer; + } + + operator const T * () const { return GetString(); } + + //Always preserves the existing content + T * OpenStringBuffer(SIZE_T count) + { + T * result = NULL; + if (Resize(count)) + { + result = (T *)m_buffer; + } + return result; + } + + //count should not include the terminating null + void CloseBuffer(SIZE_T count) + { + if (m_count > count) + m_count = count; + + NullTerminate(); + return; + } + + //Call this with the best estimate if you want to + //prevent possible reallocations on further operations + BOOL Reserve(SIZE_T count) + { + SIZE_T endpos = m_count; + + if (!Resize(count)) + return FALSE; + + m_count = endpos; + NullTerminate(); + + return TRUE; + } + + //count Should not include the terminating null + BOOL Append(const T * buffer, SIZE_T count) + { + SIZE_T endpos = m_count; + if (!Resize(m_count + count)) + return FALSE; + + CopyMemory(&m_buffer[endpos], buffer, (count + 1) * sizeof(T)); + NullTerminate(); + return TRUE; + } + + BOOL Append(const StackString &s) + { + return Append(s.GetString(), s.GetCount()); + } + + BOOL IsEmpty() + { + return 0 == m_buffer[0]; + } + + void Clear() + { + m_count = 0; + NullTerminate(); + } + ~StackString() + { + DeleteBuffer(); + } +}; + +#if _DEBUG +typedef StackString<32, CHAR> PathCharString; +typedef StackString<32, WCHAR> PathWCharString; +#else +typedef StackString<260, CHAR> PathCharString; +typedef StackString<260, WCHAR> PathWCharString; +#endif +#endif + +// Some Helper Definitions +BOOL +PAL_GetPALDirectoryW( + PathWCharString& lpDirectoryName); +BOOL +PAL_GetPALDirectoryA( + PathCharString& lpDirectoryName); +DWORD +GetCurrentDirectoryA( + PathCharString& lpBuffer); +void +FILEDosToUnixPathA( + PathCharString& lpPath); diff --git a/src/pal/src/include/pal/synchcache.hpp b/src/pal/src/include/pal/synchcache.hpp new file mode 100644 index 0000000000..c172842292 --- /dev/null +++ b/src/pal/src/include/pal/synchcache.hpp @@ -0,0 +1,397 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/synchcache.hpp + +Abstract: + Simple look-aside cache for unused objects with default + constructor or no constructor + + + +--*/ + +#ifndef _SYNCH_CACHE_H_ +#define _SYNCH_CACHE_H_ + +#include "pal/thread.hpp" +#include "pal/malloc.hpp" + +namespace CorUnix +{ + template <typename T> class CSynchCache + { + typedef union _USynchCacheStackNode + { + union _USynchCacheStackNode * next; + BYTE objraw[sizeof(T)]; + } USynchCacheStackNode; + + static const int MaxDepth = 256; + + Volatile<USynchCacheStackNode*> m_pHead; + CRITICAL_SECTION m_cs; + Volatile<int> m_iDepth; + int m_iMaxDepth; +#ifdef _DEBUG + int m_iMaxTrackedDepth; +#endif + + void Lock(CPalThread * pthrCurrent) + { InternalEnterCriticalSection(pthrCurrent, &m_cs); } + void Unlock(CPalThread * pthrCurrent) + { InternalLeaveCriticalSection(pthrCurrent, &m_cs); } + + public: + CSynchCache(int iMaxDepth = MaxDepth) : + m_pHead(NULL), + m_iDepth(0), + m_iMaxDepth(iMaxDepth) +#ifdef _DEBUG + ,m_iMaxTrackedDepth(0) +#endif + { + InternalInitializeCriticalSection(&m_cs); + if (m_iMaxDepth < 0) + { + m_iMaxDepth = 0; + } + } + + ~CSynchCache() + { + Flush(NULL, true); + InternalDeleteCriticalSection(&m_cs); + } + +#ifdef _DEBUG + int GetMaxTrackedDepth() { return m_iMaxTrackedDepth; } +#endif + + T * Get(CPalThread * pthrCurrent) + { + T * pObj = NULL; + + Get(pthrCurrent, 1, &pObj); + return pObj; + } + + int Get(CPalThread * pthrCurrent, int n, T ** ppObjs) + { + void * pvObjRaw; + USynchCacheStackNode * pNode; + int i = 0,j; + + Lock(pthrCurrent); + pNode = m_pHead; + while (pNode && i < n) + { + ppObjs[i] = (T *)pNode; + pNode = pNode->next; + i++; + } + m_pHead = pNode; + m_iDepth -= i; + +#ifdef _DEBUG + if (NULL == m_pHead && m_iDepth != 0) + { + // Can't use ASSERT here, since this is header + // is included by other headers with inline methods + // which causes template instatiation in the header + // where the DEBUG CHANNEL is not defined and cannot + // be defined + fprintf(stderr,"SYNCCACHE: Invalid cache depth value"); + DebugBreak(); + } +#endif // _DEBUG + + Unlock(pthrCurrent); + + for (j=i;j<n;j++) + { + pvObjRaw = (void *) InternalNew<USynchCacheStackNode>(); + if (NULL == pvObjRaw) + break; +#ifdef _DEBUG + memset(pvObjRaw, 0, sizeof(USynchCacheStackNode)); +#endif + ppObjs[j] = reinterpret_cast<T*>(pvObjRaw); + } + + for (i=0;i<j;i++) + { + new ((void *)ppObjs[i]) T; + } + + return j; + } + + void Add(CPalThread * pthrCurrent, T * pobj) + { + USynchCacheStackNode * pNode = reinterpret_cast<USynchCacheStackNode *>(pobj); + + if (NULL == pobj) + { + return; + } + + pobj->~T(); + + Lock(pthrCurrent); + if (m_iDepth < m_iMaxDepth) + { +#ifdef _DEBUG + if (m_iDepth > m_iMaxTrackedDepth) + { + m_iMaxTrackedDepth = m_iDepth; + } +#endif + pNode->next = m_pHead; + m_pHead = pNode; + m_iDepth++; + } + else + { + InternalDelete((char *)pNode); + } + Unlock(pthrCurrent); + } + + void Flush(CPalThread * pthrCurrent, bool fDontLock = false) + { + USynchCacheStackNode * pNode, * pTemp; + + if (!fDontLock) + { + Lock(pthrCurrent); + } + pNode = m_pHead; + m_pHead = NULL; + m_iDepth = 0; + if (!fDontLock) + { + Unlock(pthrCurrent); + } + + while (pNode) + { + pTemp = pNode; + pNode = pNode->next; + InternalDelete((char *)pTemp); + } + } + }; + + template <typename T> class CSHRSynchCache + { + union _USHRSynchCacheStackNode; // fwd declaration + typedef struct _SHRCachePTRs + { + union _USHRSynchCacheStackNode * pNext; + SharedID shrid; + } SHRCachePTRs; + typedef union _USHRSynchCacheStackNode + { + SHRCachePTRs pointers; + BYTE objraw[sizeof(T)]; + } USHRSynchCacheStackNode; + + static const int MaxDepth = 256; + static const int PreAllocFactor = 10; // Everytime a Get finds no available + // cached raw intances, it preallocates + // MaxDepth/PreAllocFactor new raw + // instances and store them into the + // cache before continuing + + Volatile<USHRSynchCacheStackNode*> m_pHead; + CRITICAL_SECTION m_cs; + Volatile<int> m_iDepth; + int m_iMaxDepth; +#ifdef _DEBUG + int m_iMaxTrackedDepth; +#endif + + void Lock(CPalThread * pthrCurrent) + { InternalEnterCriticalSection(pthrCurrent, &m_cs); } + void Unlock(CPalThread * pthrCurrent) + { InternalLeaveCriticalSection(pthrCurrent, &m_cs); } + + public: + CSHRSynchCache(int iMaxDepth = MaxDepth) : + m_pHead(NULL), + m_iDepth(0), + m_iMaxDepth(iMaxDepth) +#ifdef _DEBUG + ,m_iMaxTrackedDepth(0) +#endif + { + InternalInitializeCriticalSection(&m_cs); + if (m_iMaxDepth < 0) + { + m_iMaxDepth = 0; + } + } + + ~CSHRSynchCache() + { + Flush(NULL, true); + InternalDeleteCriticalSection(&m_cs); + } + +#ifdef _DEBUG + int GetMaxTrackedDepth() { return m_iMaxTrackedDepth; } +#endif + + SharedID Get(CPalThread * pthrCurrent) + { + SharedID shridObj = NULLSharedID; + + Get(pthrCurrent, 1, &shridObj); + return shridObj; + } + + int Get(CPalThread * pthrCurrent, int n, SharedID * shridpObjs) + { + SharedID shridObj; + void * pvObjRaw = NULL; + USHRSynchCacheStackNode * pNode; + int i = 0, j, k; + + Lock(pthrCurrent); + pNode = m_pHead; + while (pNode && i < n) + { + shridpObjs[i] = pNode->pointers.shrid; + pvObjRaw = (void *)pNode; + pNode = pNode->pointers.pNext; + i++; + } + m_pHead = pNode; + m_iDepth -= i; + +#ifdef _DEBUG + if (NULL == m_pHead && m_iDepth != 0) + { + // Can't use ASSERT here, since this is header + // (see comment above) + fprintf(stderr,"SYNCCACHE: Invalid cache depth value"); + DebugBreak(); + } +#endif // _DEBUG + + if (0 == m_iDepth) + { + for (k=0; k<m_iMaxDepth/PreAllocFactor-n+i; k++) + { + shridObj = RawSharedObjectAlloc(sizeof(USHRSynchCacheStackNode), DefaultSharedPool); + if (NULLSharedID == shridObj) + { + Flush(pthrCurrent, true); + break; + } + pNode = SharedIDToTypePointer(USHRSynchCacheStackNode, shridObj); +#ifdef _DEBUG + memset(reinterpret_cast<void*>(pNode), 0, sizeof(USHRSynchCacheStackNode)); +#endif + pNode->pointers.shrid = shridObj; + pNode->pointers.pNext = m_pHead; + m_pHead = pNode; + m_iDepth++; + } + } + + Unlock(pthrCurrent); + + for (j=i;j<n;j++) + { + shridObj = RawSharedObjectAlloc(sizeof(USHRSynchCacheStackNode), DefaultSharedPool); + if (NULLSharedID == shridObj) + break; +#ifdef _DEBUG + pvObjRaw = SharedIDToPointer(shridObj); + memset(pvObjRaw, 0, sizeof(USHRSynchCacheStackNode)); +#endif + shridpObjs[j] = shridObj; + } + + for (i=0;i<j;i++) + { + pvObjRaw = SharedIDToPointer(shridpObjs[i]); + new (pvObjRaw) T; + } + + return j; + } + + void Add(CPalThread * pthrCurrent, SharedID shridObj) + { + if (NULLSharedID == shridObj) + { + return; + } + + USHRSynchCacheStackNode * pNode = SharedIDToTypePointer(USHRSynchCacheStackNode, shridObj); + T * pObj = reinterpret_cast<T *>(pNode); + + pObj->~T(); + + pNode->pointers.shrid = shridObj; + + Lock(pthrCurrent); + if (m_iDepth < m_iMaxDepth) + { + m_iDepth++; +#ifdef _DEBUG + if (m_iDepth > m_iMaxTrackedDepth) + { + m_iMaxTrackedDepth = m_iDepth; + } +#endif + pNode->pointers.pNext = m_pHead; + m_pHead = pNode; + } + else + { + RawSharedObjectFree(shridObj); + } + Unlock(pthrCurrent); + } + + void Flush(CPalThread * pthrCurrent, bool fDontLock = false) + { + USHRSynchCacheStackNode * pNode, * pTemp; + SharedID shridTemp; + + if (!fDontLock) + { + Lock(pthrCurrent); + } + pNode = m_pHead; + m_pHead = NULL; + m_iDepth = 0; + if (!fDontLock) + { + Unlock(pthrCurrent); + } + + while (pNode) + { + pTemp = pNode; + pNode = pNode->pointers.pNext; + shridTemp = pTemp->pointers.shrid; + RawSharedObjectFree(shridTemp); + } + } + }; +} + +#endif // _SYNCH_CACHE_H_ + diff --git a/src/pal/src/include/pal/synchobjects.hpp b/src/pal/src/include/pal/synchobjects.hpp new file mode 100644 index 0000000000..aa3a8f1aa6 --- /dev/null +++ b/src/pal/src/include/pal/synchobjects.hpp @@ -0,0 +1,216 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/synchobjects.hpp + +Abstract: + Header file for synchronization manager and controllers + + + +--*/ + +#ifndef _SINCHOBJECTS_HPP_ +#define _SINCHOBJECTS_HPP_ + +#include "corunix.hpp" +#include "threadinfo.hpp" +#include "mutex.hpp" +#include "shm.hpp" +#include "list.h" + +#include <pthread.h> + +#define SharedID SHMPTR +#define SharedPoolId ULONG_PTR +#define DefaultSharedPool ((ULONG_PTR)0) +#define NULLSharedID ((SHMPTR)NULL) +#define SharedIDToPointer(shID) SHMPTR_TO_TYPED_PTR(PVOID, shID) +#define SharedIDToTypePointer(TYPE,shID) SHMPTR_TO_TYPED_PTR(TYPE, shID) +#define RawSharedObjectAlloc(szSize, shPoolId) SHMalloc(szSize) +#define RawSharedObjectFree(shID) SHMfree(shID) + +namespace CorUnix +{ + DWORD InternalWaitForMultipleObjectsEx( + CPalThread * pthrCurrent, + DWORD nCount, + CONST HANDLE *lpHandles, + BOOL bWaitAll, + DWORD dwMilliseconds, + BOOL bAlertable); + + PAL_ERROR InternalSleepEx( + CPalThread * pthrCurrent, + DWORD dwMilliseconds, + BOOL bAlertable); + + enum THREAD_STATE + { + TS_IDLE, + TS_STARTING, + TS_RUNNING, + TS_FAILED, + TS_DONE, + }; + + // forward declarations + struct _ThreadWaitInfo; + struct _WaitingThreadsListNode; + class CSynchData; + + typedef struct _WaitingThreadsListNode * PWaitingThreadsListNode; + typedef struct _OwnedObjectsListNode * POwnedObjectsListNode; + typedef struct _ThreadApcInfoNode * PThreadApcInfoNode; + + typedef struct _ThreadWaitInfo + { + WaitType wtWaitType; + WaitDomain wdWaitDomain; + LONG lObjCount; + LONG lSharedObjCount; + CPalThread * pthrOwner; + PWaitingThreadsListNode rgpWTLNodes[MAXIMUM_WAIT_OBJECTS]; + + _ThreadWaitInfo() : wtWaitType(SingleObject), wdWaitDomain(LocalWait), + lObjCount(0), lSharedObjCount(0), + pthrOwner(NULL) {} + } ThreadWaitInfo; + + typedef struct _ThreadNativeWaitData + { + pthread_mutex_t mutex; + pthread_cond_t cond; + int iPred; + DWORD dwObjectIndex; + ThreadWakeupReason twrWakeupReason; + bool fInitialized; + + _ThreadNativeWaitData() : + iPred(0), + dwObjectIndex(0), + twrWakeupReason(WaitSucceeded), + fInitialized(false) + { + } + + ~_ThreadNativeWaitData(); + } ThreadNativeWaitData; + + class CThreadSynchronizationInfo : public CThreadInfoInitializer + { + friend class CPalSynchronizationManager; + friend class CSynchWaitController; + + THREAD_STATE m_tsThreadState; + SharedID m_shridWaitAwakened; + Volatile<LONG> m_lLocalSynchLockCount; + Volatile<LONG> m_lSharedSynchLockCount; + LIST_ENTRY m_leOwnedObjsList; + + CRITICAL_SECTION m_ownedNamedMutexListLock; + NamedMutexProcessData *m_ownedNamedMutexListHead; + + ThreadNativeWaitData m_tnwdNativeData; + ThreadWaitInfo m_twiWaitInfo; + +#ifdef SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING + static const int PendingSignalingsArraySize = 10; + LONG m_lPendingSignalingCount; + CPalThread * m_rgpthrPendingSignalings[PendingSignalingsArraySize]; + LIST_ENTRY m_lePendingSignalingsOverflowList; +#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING + + public: + + CThreadSynchronizationInfo(); + virtual ~CThreadSynchronizationInfo(); + + // + // CThreadInfoInitializer methods + // + virtual PAL_ERROR InitializePreCreate(void); + + virtual PAL_ERROR InitializePostCreate( + CPalThread *pthrCurrent, + SIZE_T threadId, + DWORD dwLwpId + ); + + THREAD_STATE GetThreadState(void) + { + return m_tsThreadState; + }; + + void SetThreadState(THREAD_STATE tsThreadState) + { + m_tsThreadState = tsThreadState; + }; + + ThreadNativeWaitData * GetNativeData() + { + return &m_tnwdNativeData; + } + +#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING + PAL_ERROR RunDeferredThreadConditionSignalings(); +#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING + + // NOTE: the following methods provide non-synchronized access to + // the list of owned objects for this thread. Any thread + // accessing this list MUST own the appropriate + // synchronization lock(s). + void AddObjectToOwnedList(POwnedObjectsListNode pooln); + void RemoveObjectFromOwnedList(POwnedObjectsListNode pooln); + POwnedObjectsListNode RemoveFirstObjectFromOwnedList(void); + + void AddOwnedNamedMutex(NamedMutexProcessData *processData); + void RemoveOwnedNamedMutex(NamedMutexProcessData *processData); + NamedMutexProcessData *RemoveFirstOwnedNamedMutex(); + bool OwnsNamedMutex(NamedMutexProcessData *processData); + + // The following methods provide access to the native wait lock for + // those implementations that need a lock to protect the support for + // native thread blocking (e.g.: pthread conditions) + void AcquireNativeWaitLock(void); + void ReleaseNativeWaitLock(void); + bool TryAcquireNativeWaitLock(void); + }; + + class CThreadApcInfo : public CThreadInfoInitializer + { + friend class CPalSynchronizationManager; + + PThreadApcInfoNode m_ptainHead; + PThreadApcInfoNode m_ptainTail; + + public: + CThreadApcInfo() : + m_ptainHead(NULL), + m_ptainTail(NULL) + { + } + }; + + class CPalSynchMgrController + { + public: + static IPalSynchronizationManager * CreatePalSynchronizationManager(); + + static PAL_ERROR StartWorker(CPalThread * pthrCurrent); + + static PAL_ERROR PrepareForShutdown(void); + + static PAL_ERROR Shutdown(CPalThread *pthrCurrent, bool fFullCleanup); + }; +} + +#endif // _SINCHOBJECTS_HPP_ + diff --git a/src/pal/src/include/pal/thread.hpp b/src/pal/src/include/pal/thread.hpp new file mode 100644 index 0000000000..e6dacd2136 --- /dev/null +++ b/src/pal/src/include/pal/thread.hpp @@ -0,0 +1,838 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/thread.hpp + +Abstract: + Header file for thread structures + + + +--*/ + +#ifndef _PAL_THREAD_HPP_ +#define _PAL_THREAD_HPP_ + +#include "corunix.hpp" +#include "shm.hpp" +#include "cs.hpp" + +#include <pthread.h> +#include <sys/syscall.h> +#if HAVE_MACH_EXCEPTIONS +#include <mach/mach.h> +#endif // HAVE_MACH_EXCEPTIONS + +#include "threadsusp.hpp" +#include "tls.hpp" +#include "synchobjects.hpp" +#include <errno.h> + +namespace CorUnix +{ + enum PalThreadType + { + UserCreatedThread, + PalWorkerThread, + SignalHandlerThread + }; + + PAL_ERROR + InternalCreateThread( + CPalThread *pThread, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + DWORD dwStackSize, + LPTHREAD_START_ROUTINE lpStartAddress, + LPVOID lpParameter, + DWORD dwCreationFlags, + PalThreadType eThreadType, + LPDWORD lpThreadId, + HANDLE *phThread + ); + + PAL_ERROR + InternalGetThreadPriority( + CPalThread *pThread, + HANDLE hTargetThread, + int *piNewPriority + ); + + PAL_ERROR + InternalSetThreadPriority( + CPalThread *pThread, + HANDLE hTargetThread, + int iNewPriority + ); + + PAL_ERROR + InternalGetThreadDataFromHandle( + CPalThread *pThread, + HANDLE hThread, + DWORD dwRightsRequired, + CPalThread **ppTargetThread, + IPalObject **ppobjThread + ); + + VOID + InternalEndCurrentThread( + CPalThread *pThread + ); + + PAL_ERROR + InternalCreateDummyThread( + CPalThread *pThread, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + CPalThread **ppDummyThread, + HANDLE *phThread + ); + + PAL_ERROR + InitializeGlobalThreadData( + void + ); + + PAL_ERROR + CreateThreadData( + CPalThread **ppThread + ); + + PAL_ERROR + CreateThreadObject( + CPalThread *pThread, + CPalThread *pNewThread, + HANDLE *phThread + ); + + PAL_ERROR + InitializeEndingThreadsData( + void + ); + + BOOL + GetThreadTimesInternal( + IN HANDLE hThread, + OUT LPFILETIME lpKernelTime, + OUT LPFILETIME lpUserTime); + +#ifdef FEATURE_PAL_SXS +#if HAVE_MACH_EXCEPTIONS + + // Structure used to return data about a single handler to a caller. + struct MachExceptionHandler + { + exception_mask_t m_mask; + exception_handler_t m_handler; + exception_behavior_t m_behavior; + thread_state_flavor_t m_flavor; + }; + + // Class abstracting previously registered Mach exception handlers for a thread. + struct CThreadMachExceptionHandlers + { + public: + // Maximum number of exception ports we hook. Must be the count + // of all bits set in the exception masks defined in machexception.h. + static const int s_nPortsMax = 6; + + // Saved exception ports, exactly as returned by + // thread_swap_exception_ports. + mach_msg_type_number_t m_nPorts; + exception_mask_t m_masks[s_nPortsMax]; + exception_handler_t m_handlers[s_nPortsMax]; + exception_behavior_t m_behaviors[s_nPortsMax]; + thread_state_flavor_t m_flavors[s_nPortsMax]; + + CThreadMachExceptionHandlers() : + m_nPorts(-1) + { + } + + // Get handler details for a given type of exception. If successful the structure pointed at by + // pHandler is filled in and true is returned. Otherwise false is returned. + bool GetHandler(exception_type_t eException, MachExceptionHandler *pHandler); + + private: + // Look for a handler for the given exception within the given handler node. Return its index if + // successful or -1 otherwise. + int GetIndexOfHandler(exception_mask_t bmExceptionMask); + }; +#endif // HAVE_MACH_EXCEPTIONS +#endif // FEATURE_PAL_SXS + + class CThreadSEHInfo : public CThreadInfoInitializer + { + public: +#if !HAVE_MACH_EXCEPTIONS + BOOL safe_state; + int signal_code; +#endif // !HAVE_MACH_EXCEPTIONSG + + CThreadSEHInfo() + { + }; + }; + + /* In the windows CRT there is a constant defined for the max width + of a _ecvt conversion. That constant is 348. 348 for the value, plus + the exponent value, decimal, and sign if required. */ +#define ECVT_MAX_COUNT_SIZE 348 +#define ECVT_MAX_BUFFER_SIZE 357 + + /*STR_TIME_SIZE is defined as 26 the size of the + return val by ctime_r*/ +#define STR_TIME_SIZE 26 + + class CThreadCRTInfo : public CThreadInfoInitializer + { + public: + CHAR * strtokContext; // Context for strtok function + WCHAR * wcstokContext; // Context for wcstok function + struct PAL_tm localtimeBuffer; // Buffer for localtime function + CHAR ctimeBuffer[ STR_TIME_SIZE ]; // Buffer for ctime function + CHAR ECVTBuffer[ ECVT_MAX_BUFFER_SIZE ]; // Buffer for _ecvt function. + + CThreadCRTInfo() : + strtokContext(NULL), + wcstokContext(NULL) + { + ZeroMemory(&localtimeBuffer, sizeof(localtimeBuffer)); + ZeroMemory(ctimeBuffer, sizeof(ctimeBuffer)); + ZeroMemory(ECVTBuffer, sizeof(ECVTBuffer)); + }; + }; + + class CPalThread + { + friend + PAL_ERROR + CorUnix::InternalCreateThread( + CPalThread *, + LPSECURITY_ATTRIBUTES, + DWORD, + LPTHREAD_START_ROUTINE, + LPVOID, + DWORD, + PalThreadType, + LPDWORD, + HANDLE* + ); + + friend + PAL_ERROR + InternalCreateDummyThread( + CPalThread *pThread, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + CPalThread **ppDummyThread, + HANDLE *phThread + ); + + friend + PAL_ERROR + InternalSetThreadPriority( + CPalThread *, + HANDLE, + int + ); + + friend + PAL_ERROR + InitializeGlobalThreadData( + void + ); + + friend + PAL_ERROR + CreateThreadData( + CPalThread **ppThread + ); + + friend + PAL_ERROR + CreateThreadObject( + CPalThread *pThread, + CPalThread *pNewThread, + HANDLE *phThread + ); + + friend CatchHardwareExceptionHolder; + + private: + + CPalThread *m_pNext; + DWORD m_dwExitCode; + BOOL m_fExitCodeSet; + CRITICAL_SECTION m_csLock; + bool m_fLockInitialized; + bool m_fIsDummy; + + // + // Minimal reference count, used primarily for cleanup purposes. A + // new thread object has an initial refcount of 1. This initial + // reference is removed by CorUnix::InternalEndCurrentThread. + // + // The only other spot the refcount is touched is from within + // CPalObjectBase::ReleaseReference -- incremented before the + // destructors for an ojbect are called, and decremented afterwords. + // This permits the freeing of the thread structure to happen after + // the freeing of the enclosing thread object has completed. + // + + LONG m_lRefCount; + + // + // The IPalObject for this thread. The thread will release its reference + // to this object when it exits. + // + + IPalObject *m_pThreadObject; + + // + // Thread ID info + // + + SIZE_T m_threadId; + DWORD m_dwLwpId; + pthread_t m_pthreadSelf; + +#if HAVE_MACH_THREADS + mach_port_t m_machPortSelf; +#endif + + // > 0 when there is an exception holder which causes h/w + // exceptions to be sent down the C++ exception chain. + int m_hardwareExceptionHolderCount; + + // + // Start info + // + + LPTHREAD_START_ROUTINE m_lpStartAddress; + LPVOID m_lpStartParameter; + BOOL m_bCreateSuspended; + + int m_iThreadPriority; + PalThreadType m_eThreadType; + + // + // pthread mutex / condition variable for gating thread startup. + // InternalCreateThread waits on the condition variable to determine + // when the new thread has reached passed all failure points in + // the entry routine + // + + pthread_mutex_t m_startMutex; + pthread_cond_t m_startCond; + bool m_fStartItemsInitialized; + bool m_fStartStatus; + bool m_fStartStatusSet; + + // Base address of the stack of this thread + void* m_stackBase; + // Limit address of the stack of this thread + void* m_stackLimit; + + // The default stack size of a newly created thread (currently 256KB) + // when the dwStackSize paramter of PAL_CreateThread() + // is zero. This value can be set by setting the + // environment variable PAL_THREAD_DEFAULT_STACK_SIZE + // (the value should be in bytes and in hex). + static DWORD s_dwDefaultThreadStackSize; + + // + // The thread entry routine (called from InternalCreateThread) + // + + static void* ThreadEntry(void * pvParam); + +#ifdef FEATURE_PAL_SXS + // + // Data for PAL side-by-side support + // + + private: + // This is set whenever this thread is currently executing within + // a region of code that depends on this instance of the PAL + // in the process. + bool m_fInPal; + +#if HAVE_MACH_EXCEPTIONS + // Record of Mach exception handlers that were already registered when we register our own CoreCLR + // specific handlers. + CThreadMachExceptionHandlers m_sMachExceptionHandlers; +#endif // HAVE_MACH_EXCEPTIONS +#endif // FEATURE_PAL_SXS + + public: + + // + // Embedded information for areas owned by other subsystems + // + + CThreadSynchronizationInfo synchronizationInfo; + CThreadSuspensionInfo suspensionInfo; + CThreadSEHInfo sehInfo; + CThreadTLSInfo tlsInfo; + CThreadApcInfo apcInfo; + CThreadCRTInfo crtInfo; + + CPalThread() + : + m_pNext(NULL), + m_dwExitCode(STILL_ACTIVE), + m_fExitCodeSet(FALSE), + m_fLockInitialized(FALSE), + m_fIsDummy(FALSE), + m_lRefCount(1), + m_pThreadObject(NULL), + m_threadId(0), + m_dwLwpId(0), + m_pthreadSelf(0), +#if HAVE_MACH_THREADS + m_machPortSelf(0), +#endif + m_hardwareExceptionHolderCount(0), + m_lpStartAddress(NULL), + m_lpStartParameter(NULL), + m_bCreateSuspended(FALSE), + m_iThreadPriority(THREAD_PRIORITY_NORMAL), + m_eThreadType(UserCreatedThread), + m_fStartItemsInitialized(FALSE), + m_fStartStatus(FALSE), + m_fStartStatusSet(FALSE), + m_stackBase(NULL), + m_stackLimit(NULL) +#ifdef FEATURE_PAL_SXS + , m_fInPal(TRUE) +#endif // FEATURE_PAL_SXS + { + }; + + virtual ~CPalThread(); + + PAL_ERROR + RunPreCreateInitializers( + void + ); + + // + // m_threadId and m_dwLwpId must be set before calling + // RunPostCreateInitializers + // + + PAL_ERROR + RunPostCreateInitializers( + void + ); + + // + // SetStartStatus is called by THREADEntry or InternalSuspendNewThread + // to inform InternalCreateThread of the results of the thread's + // initialization. InternalCreateThread calls WaitForStartStatus to + // obtain this information (and will not return to its caller until + // the info is available). + // + + void + SetStartStatus( + bool fStartSucceeded + ); + + bool + WaitForStartStatus( + void + ); + + void + Lock( + CPalThread *pThread + ) + { + InternalEnterCriticalSection(pThread, &m_csLock); + }; + + void + Unlock( + CPalThread *pThread + ) + { + InternalLeaveCriticalSection(pThread, &m_csLock); + }; + + // + // The following three methods provide access to the + // native lock used to protect thread native wait data. + // + + void + AcquireNativeWaitLock( + void + ) + { + synchronizationInfo.AcquireNativeWaitLock(); + } + + void + ReleaseNativeWaitLock( + void + ) + { + synchronizationInfo.ReleaseNativeWaitLock(); + } + + bool + TryAcquireNativeWaitLock( + void + ) + { + return synchronizationInfo.TryAcquireNativeWaitLock(); + } + + static void + SetLastError( + DWORD dwLastError + ) + { + // Reuse errno to store last error + errno = dwLastError; + }; + + static DWORD + GetLastError( + void + ) + { + // Reuse errno to store last error + return errno; + }; + + void + SetExitCode( + DWORD dwExitCode + ) + { + m_dwExitCode = dwExitCode; + m_fExitCodeSet = TRUE; + }; + + BOOL + GetExitCode( + DWORD *pdwExitCode + ) + { + *pdwExitCode = m_dwExitCode; + return m_fExitCodeSet; + }; + + SIZE_T + GetThreadId( + void + ) + { + return m_threadId; + }; + + DWORD + GetLwpId( + void + ) + { + return m_dwLwpId; + }; + + pthread_t + GetPThreadSelf( + void + ) + { + return m_pthreadSelf; + }; + +#if HAVE_MACH_THREADS + mach_port_t + GetMachPortSelf( + void + ) + { + return m_machPortSelf; + }; +#endif + + bool + IsHardwareExceptionsEnabled() + { + return m_hardwareExceptionHolderCount > 0; + } + + LPTHREAD_START_ROUTINE + GetStartAddress( + void + ) + { + return m_lpStartAddress; + }; + + LPVOID + GetStartParameter( + void + ) + { + return m_lpStartParameter; + }; + + BOOL + GetCreateSuspended( + void + ) + { + return m_bCreateSuspended; + }; + + PalThreadType + GetThreadType( + void + ) + { + return m_eThreadType; + }; + + int + GetThreadPriority( + void + ) + { + return m_iThreadPriority; + }; + + IPalObject * + GetThreadObject( + void + ) + { + return m_pThreadObject; + } + + BOOL + IsDummy( + void + ) + { + return m_fIsDummy; + }; + + CPalThread* + GetNext( + void + ) + { + return m_pNext; + }; + + void + SetNext( + CPalThread *pNext + ) + { + m_pNext = pNext; + }; + + void + AddThreadReference( + void + ); + + void + ReleaseThreadReference( + void + ); + + // Get base address of the current thread's stack + static + void * + GetStackBase( + void + ); + + // Get cached base address of this thread's stack + // Can be called only for the current thread. + void * + GetCachedStackBase( + void + ); + + // Get limit address of the current thread's stack + static + void * + GetStackLimit( + void + ); + + // Get cached limit address of this thread's stack + // Can be called only for the current thread. + void * + GetCachedStackLimit( + void + ); + +#ifdef FEATURE_PAL_SXS + // + // Functions for PAL side-by-side support + // + + // This function needs to be called on a thread when it enters + // a region of code that depends on this instance of the PAL + // in the process. + PAL_ERROR Enter(PAL_Boundary boundary); + + // This function needs to be called on a thread when it leaves + // a region of code that depends on this instance of the PAL + // in the process. + PAL_ERROR Leave(PAL_Boundary boundary); + + // Returns TRUE whenever this thread is executing in a region + // of code that depends on this instance of the PAL in the process. + BOOL IsInPal() + { + return m_fInPal; + }; + +#if HAVE_MACH_EXCEPTIONS + // Hook Mach exceptions, i.e., call thread_swap_exception_ports + // to replace the thread's current exception ports with our own. + // The previously active exception ports are saved. Called when + // this thread enters a region of code that depends on this PAL. + // Should only fail on internal errors. + PAL_ERROR EnableMachExceptions(); + + // Unhook Mach exceptions, i.e., call thread_set_exception_ports + // to restore the thread's exception ports with those we saved + // in EnableMachExceptions. Called when this thread leaves a + // region of code that depends on this PAL. Should only fail + // on internal errors. + PAL_ERROR DisableMachExceptions(); + + // The exception handling thread needs to be able to get at the list of handlers that installing our + // own handler on a thread has displaced (in case we need to forward an exception that we don't want + // to handle). + CThreadMachExceptionHandlers *GetSavedMachHandlers() + { + return &m_sMachExceptionHandlers; + } +#endif // HAVE_MACH_EXCEPTIONS +#endif // FEATURE_PAL_SXS + }; + +#if defined(FEATURE_PAL_SXS) + extern "C" CPalThread *CreateCurrentThreadData(); +#endif // FEATURE_PAL_SXS + + inline CPalThread *GetCurrentPalThread() + { + return reinterpret_cast<CPalThread*>(pthread_getspecific(thObjKey)); + } + + inline CPalThread *InternalGetCurrentThread() + { + CPalThread *pThread = GetCurrentPalThread(); +#if defined(FEATURE_PAL_SXS) + if (pThread == nullptr) + pThread = CreateCurrentThreadData(); +#endif // FEATURE_PAL_SXS + return pThread; + } + +/*** + + $$TODO: These are needed only to support cross-process thread duplication + + class CThreadImmutableData + { + public: + DWORD dwProcessId; + }; + + class CThreadSharedData + { + public: + DWORD dwThreadId; + DWORD dwExitCode; + }; +***/ + + // + // The process local information for a thread is just a pointer + // to the underlying CPalThread object. + // + + class CThreadProcessLocalData + { + public: + CPalThread *pThread; + }; + + extern CObjectType otThread; +} + +BOOL +TLSInitialize( + void + ); + +VOID +TLSCleanup( + void + ); + +VOID +WaitForEndingThreads( + void + ); + +extern int free_threads_spinlock; + +extern PAL_ActivationFunction g_activationFunction; +extern PAL_SafeActivationCheckFunction g_safeActivationCheckFunction; + +/*++ +Macro: + THREADSilentGetCurrentThreadId + +Abstract: + Same as GetCurrentThreadId, but it doesn't output any traces. + It is useful for tracing functions to display the thread ID + without generating any new traces. + + TODO: how does the perf of pthread_self compare to + InternalGetCurrentThread when we find the thread in the + cache? + + If the perf of pthread_self is comparable to that of the stack + bounds based lookaside system, why aren't we using it in the + cache? + + In order to match the thread ids that debuggers use at least for + linux we need to use gettid(). + +--*/ +#if defined(__linux__) +#define THREADSilentGetCurrentThreadId() (SIZE_T)syscall(SYS_gettid) +#elif defined(__APPLE__) +inline SIZE_T THREADSilentGetCurrentThreadId() { + uint64_t tid; + pthread_threadid_np(pthread_self(), &tid); + return (SIZE_T)tid; +} +#elif defined(__NetBSD__) +#include <lwp.h> +#define THREADSilentGetCurrentThreadId() (SIZE_T)_lwp_self() +#else +#define THREADSilentGetCurrentThreadId() (SIZE_T)pthread_self() +#endif + +#endif // _PAL_THREAD_HPP_ diff --git a/src/pal/src/include/pal/threadinfo.hpp b/src/pal/src/include/pal/threadinfo.hpp new file mode 100644 index 0000000000..93ba0ababd --- /dev/null +++ b/src/pal/src/include/pal/threadinfo.hpp @@ -0,0 +1,89 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/threadinfo.hpp + +Abstract: + Header file for thread info initialzer + + + +--*/ + +#ifndef _PAL_THREADINFO_H_ +#define _PAL_THREADINFO_H_ + +#include "corunix.hpp" + +namespace CorUnix +{ + // + // There are a number of different functional areas for which we need to + // store per-thread data: + // * synchronization + // * structure exception handling + // * asynchronous procedure calls + // * thread suspension + // * thread-local storage + // * CRT per-thread buffers + // + // For each of the above functional areas we build a class that stores + // the necessary data. An instance of each of these classes is embedded + // in the main thread class. The classes must not have any failure paths + // in their constructors. Each class inherits from a common parent class + // that exposes two virtual initialization routines (which may return an + // error). The first initialization routine is called after the thread + // object is allocated, but before the new thread is created. Any + // initialization that is not dependant on knowledge of the new thread's + // ID (and by extension need not run in the context of the new thread) + // should take place in the first routine. Work that must run in the + // context of the new thread or that must know the new thread's ID + // should take place in the second initialization routine. + // + + class CThreadInfoInitializer + { + public: + + // + // InitializePreCreate is called before the new thread is started. + // Any allocations or other initializations that may fail that do + // not need to run in the context of the new thread (or know the + // new thread's ID) should take place in this routine. + // + + virtual + PAL_ERROR + InitializePreCreate( + void + ) + { + return NO_ERROR; + }; + + // + // InitializePostCreate is called from within the context of the + // new thread. + // + + virtual + PAL_ERROR + InitializePostCreate( + CPalThread *pThread, + SIZE_T threadId, + DWORD dwLwpId + ) + { + return NO_ERROR; + }; + }; +} + +#endif // _PAL_THREADINFO_H_ diff --git a/src/pal/src/include/pal/threadsusp.hpp b/src/pal/src/include/pal/threadsusp.hpp new file mode 100644 index 0000000000..e1e85e265c --- /dev/null +++ b/src/pal/src/include/pal/threadsusp.hpp @@ -0,0 +1,382 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/threadsusp.hpp + +Abstract: + Declarations for thread suspension + + + +--*/ + +#ifndef _PAL_THREADSUSP_HPP +#define _PAL_THREADSUSP_HPP + +// Need this ifdef since this header is included by .c files so they can use the diagnostic function. +#ifdef __cplusplus + +// Note: do not include malloc.hpp from this header. The template InternalDelete +// needs to know the layout of class CPalThread, which includes a member of type +// CThreadSuspensionInfo, which is defined later in this header, and it is not +// yet known at this point. +// If any future change should bring this issue back, the circular dependency can +// be further broken by making the InternalDelete's CPalThread argument a +// templatized argument, so that type checking on it takes place only at +// instantiation time. +#include "pal/threadinfo.hpp" +#include "pal/thread.hpp" +#include "pal/printfcpp.hpp" +#include "pal/mutex.hpp" +#include "pal/init.h" +#if !HAVE_MACH_EXCEPTIONS +#include <signal.h> +#endif // !HAVE_MACH_EXCEPTIONS +#include <semaphore.h> +#include <sched.h> + +// We have a variety of options for synchronizing thread suspensions and resumptions between the requestor and +// target threads. Analyze the various capabilities given to us by configure and define one of three macros +// here for simplicity: +// USE_POSIX_SEMAPHORES +// USE_SYSV_SEMAPHORES +// USE_PTHREAD_CONDVARS +#if HAS_POSIX_SEMAPHORES + +// Favor posix semaphores. +#define USE_POSIX_SEMAPHORES 1 + +#if HAVE_SYS_SEMAPHORE_H +#include <sys/semaphore.h> +#endif // HAVE_SYS_SEMAPHORE_H + +#elif HAS_PTHREAD_MUTEXES && HAVE_MACH_EXCEPTIONS + +// Can only use the pthread solution if we're not using signals since pthread mutexes are not signal safe. +#define USE_PTHREAD_CONDVARS 1 + +#include <pthread.h> + +#elif HAS_SYSV_SEMAPHORES + +// SYSV semaphores are our last choice since they're shared across processes so it's possible to leak them +// on abnormal process termination. +#define USE_SYSV_SEMAPHORES 1 + +#include <sys/sem.h> +#include <sys/types.h> + +#else +#error "Don't know how to synchronize thread suspends and resumes on this platform" +#endif // HAS_POSIX_SEMAPHORES + +#include <stdarg.h> + +namespace CorUnix +{ +#ifdef _DEBUG +#define MAX_TRACKED_CRITSECS 8 +#endif + + PAL_ERROR + InternalResumeThread( + CPalThread *pthrResumer, + HANDLE hTarget, + DWORD *pdwSuspendCount + ); + + class CThreadSuspensionInfo : public CThreadInfoInitializer + { + private: + BOOL m_fPending; // TRUE if a suspension is pending on a thread (because the thread is in an unsafe region) + BOOL m_fSelfsusp; // TRUE if thread is self suspending and while thread is self suspended + BOOL m_fSuspendedForShutdown; // TRUE once the thread is suspended during PAL cleanup + int m_nBlockingPipe; // blocking pipe used for a process that was created suspended +#ifdef _DEBUG + Volatile<LONG> m_lNumThreadsSuspendedByThisThread; // number of threads that this thread has suspended; used for suspension diagnostics +#endif +#if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX + int m_nSpinlock; // thread's suspension spinlock, which is used to synchronize suspension and resumption attempts +#else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX + pthread_mutex_t m_ptmSuspmutex; // thread's suspension mutex, which is used to synchronize suspension and resumption attempts + BOOL m_fSuspmutexInitialized; +#endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX +#if USE_POSIX_SEMAPHORES + sem_t m_semSusp; // suspension semaphore + sem_t m_semResume; // resumption semaphore + BOOL m_fSemaphoresInitialized; +#elif USE_SYSV_SEMAPHORES + // necessary id's and sembuf structures for SysV semaphores + int m_nSemsuspid; // id for the suspend semaphore + int m_nSemrespid; // id for the resume semaphore + struct sembuf m_sbSemwait; // struct representing a wait operation + struct sembuf m_sbSempost; // struct representing a post operation +#elif USE_PTHREAD_CONDVARS + pthread_cond_t m_condSusp; // suspension condition variable + pthread_mutex_t m_mutexSusp; // mutex associated with the condition above + BOOL m_fSuspended; // set to true once the suspend has been acknowledged + + pthread_cond_t m_condResume; // resumption condition variable + pthread_mutex_t m_mutexResume; // mutex associated with the condition above + BOOL m_fResumed; // set to true once the resume has been acknowledged + + BOOL m_fSemaphoresInitialized; +#endif // USE_POSIX_SEMAPHORES + + /* Most of the variables above are either accessed by a thread + holding the appropriate suspension mutex(es) or are only + accessed by their own threads (and thus don't require + synchronization). + + m_fPending, m_fSuspendedForShutdown, + m_fSuspendSignalSent, and m_fResumeSignalSent + may be set by a different thread than the owner and thus + require synchronization. + + m_fSelfsusp is set to TRUE only by its own thread but may be later + accessed by other threads. + + m_lNumThreadsSuspendedByThisThread is accessed by its owning + thread and therefore does not require synchronization. */ + +#ifdef _DEBUG + VOID + IncrNumThreadsSuspendedByThisThread( + ) + { + InterlockedIncrement(&m_lNumThreadsSuspendedByThisThread); + }; + + VOID + DecrNumThreadsSuspendedByThisThread( + ) + { + InterlockedDecrement(&m_lNumThreadsSuspendedByThisThread); + }; +#endif + + VOID + AcquireSuspensionLocks( + CPalThread *pthrSuspender, + CPalThread *pthrTarget + ); + + VOID + ReleaseSuspensionLocks( + CPalThread *pthrSuspender, + CPalThread *pthrTarget + ); + +#if USE_POSIX_SEMAPHORES + sem_t* + GetSuspendSemaphore( + void + ) + { + return &m_semSusp; + }; + + sem_t* + GetResumeSemaphore( + void + ) + { + return &m_semResume; + }; +#elif USE_SYSV_SEMAPHORES + int + GetSuspendSemaphoreId( + void + ) + { + return m_nSemsuspid; + }; + + sembuf* + GetSemaphorePostBuffer( + void + ) + { + return &m_sbSempost; + }; +#endif // USE_POSIX_SEMAPHORES + +#if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX + LONG* + GetSuspensionSpinlock( + void + ) + { + return &m_nSpinlock; + } +#else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX + pthread_mutex_t* + GetSuspensionMutex( + void + ) + { + return &m_ptmSuspmutex; + } +#endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX + + void + SetSuspPending( + BOOL fPending + ) + { + m_fPending = fPending; + }; + + BOOL + GetSuspPending( + void + ) + { + return m_fPending; + }; + + void + SetSelfSusp( + BOOL fSelfsusp + ) + { + m_fSelfsusp = fSelfsusp; + }; + + BOOL + GetSelfSusp( + void + ) + { + return m_fSelfsusp; + }; + + void + PostOnSuspendSemaphore(); + + void + WaitOnSuspendSemaphore(); + + void + PostOnResumeSemaphore(); + + void + WaitOnResumeSemaphore(); + + static + BOOL + TryAcquireSuspensionLock( + CPalThread* pthrTarget + ); + + int GetBlockingPipe( + void + ) + { + return m_nBlockingPipe; + }; + + public: + virtual PAL_ERROR InitializePreCreate(); + + CThreadSuspensionInfo() + : m_fPending(FALSE) + , m_fSelfsusp(FALSE) + , m_fSuspendedForShutdown(FALSE) + , m_nBlockingPipe(-1) +#ifdef _DEBUG + , m_lNumThreadsSuspendedByThisThread(0) +#endif // _DEBUG +#if !DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX + , m_fSuspmutexInitialized(FALSE) +#endif +#if USE_POSIX_SEMAPHORES || USE_PTHREAD_CONDVARS + , m_fSemaphoresInitialized(FALSE) +#endif + { + InitializeSuspensionLock(); + }; + + virtual ~CThreadSuspensionInfo(); + +#ifdef _DEBUG + LONG + GetNumThreadsSuspendedByThisThread( + void + ) + { + return m_lNumThreadsSuspendedByThisThread; + }; +#endif // _DEBUG + +#if USE_SYSV_SEMAPHORES + void + DestroySemaphoreIds( + void + ); +#endif + void + SetSuspendedForShutdown( + BOOL fSuspendedForShutdown + ) + { + m_fSuspendedForShutdown = fSuspendedForShutdown; + }; + + BOOL + GetSuspendedForShutdown( + void + ) + { + return m_fSuspendedForShutdown; + }; + + void + AcquireSuspensionLock( + CPalThread *pthrCurrent + ); + + void + ReleaseSuspensionLock( + CPalThread *pthrCurrent + ); + + PAL_ERROR + InternalSuspendNewThreadFromData( + CPalThread *pThread + ); + + PAL_ERROR + InternalResumeThreadFromData( + CPalThread *pthrResumer, + CPalThread *pthrTarget, + DWORD *pdwSuspendCount + ); + + VOID InitializeSuspensionLock(); + + void SetBlockingPipe( + int nBlockingPipe + ) + { + m_nBlockingPipe = nBlockingPipe; + }; + }; +} //end CorUnix + +extern const BYTE WAKEUPCODE; // use for pipe reads during self suspend. +#endif // __cplusplus + +#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION +extern LONG g_ssSuspensionLock; +#endif + +#endif // _PAL_THREADSUSP_HPP + diff --git a/src/pal/src/include/pal/tls.hpp b/src/pal/src/include/pal/tls.hpp new file mode 100644 index 0000000000..a4d9926c49 --- /dev/null +++ b/src/pal/src/include/pal/tls.hpp @@ -0,0 +1,65 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/tls.hpp + +Abstract: + Header file for thread local storage + + + +--*/ + +#ifndef _PAL_TLS_HPP +#define _PAL_TLS_HPP + +#include "threadinfo.hpp" + +namespace CorUnix +{ + /* This is the number of slots available for use in TlsAlloc(). + sTlsSlotFields in thread/localstorage.c must be this number + of bits. */ +#define TLS_SLOT_SIZE 64 + + class CThreadTLSInfo : public CThreadInfoInitializer + { + public: + LPVOID tlsSlots[TLS_SLOT_SIZE]; + + virtual + PAL_ERROR + InitializePostCreate( + CPalThread *pThread, + SIZE_T threadId, + DWORD dwLwpId + ); + + CThreadTLSInfo() + { + ZeroMemory(tlsSlots, sizeof(tlsSlots)); + }; + }; + + // + // InternalGetCurrentThread obtains the CPalThread instance for the + // calling thread. That instance should only be used by the calling + // thread. If another thread will at some point need access to this + // thread information it should be given a referenced pointer to + // the IPalObject stored within the CPalThread. + // + + extern pthread_key_t thObjKey; + + CPalThread *InternalGetCurrentThread(); +} + +#endif // _PAL_TLS_HPP + diff --git a/src/pal/src/include/pal/unicode_data.h b/src/pal/src/include/pal/unicode_data.h new file mode 100644 index 0000000000..0b7fe07447 --- /dev/null +++ b/src/pal/src/include/pal/unicode_data.h @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/unicode_data.h + +Abstract: + + Data, data retrieval function declarations. + + + +--*/ + +#ifndef _UNICODE_DATA_H_ +#define _UNICODE_DATA_H_ + +#include "pal/palinternal.h" + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +#if !HAVE_COREFOUNDATION + +typedef struct +{ + WCHAR nUnicodeValue; + WORD C1_TYPE_FLAGS; + WCHAR nOpposingCase; /* 0 if no opposing case. */ + WORD rangeValue; +} UnicodeDataRec; + +/* Global variables. */ +extern CONST UnicodeDataRec UnicodeData[]; +extern CONST UINT UNICODE_DATA_SIZE; +extern CONST UINT UNICODE_DATA_DIRECT_ACCESS; + +/*++ +Function: + GetUnicodeData + This function is used to get information about a Unicode character. + +Parameters: +nUnicodeValue + The numeric value of the Unicode character to get information about. +pDataRec + The UnicodeDataRec to fill in with the data for the Unicode character. + +Return value: + TRUE if the Unicode character was found. + +--*/ +BOOL GetUnicodeData(INT nUnicodeValue, UnicodeDataRec *pDataRec); + +#endif /* !HAVE_COREFOUNDATION */ + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* _UNICODE_DATA_H_ */ diff --git a/src/pal/src/include/pal/utf8.h b/src/pal/src/include/pal/utf8.h new file mode 100644 index 0000000000..2516caafb0 --- /dev/null +++ b/src/pal/src/include/pal/utf8.h @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/utf8.h + +Abstract: + Header file for UTF-8 conversion functions. + +Revision History: + + + +--*/ + +#ifndef _PAL_UTF8_H_ +#define _PAL_UTF8_H_ + +#include <pal/palinternal.h> /* for WCHAR */ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/*++ +Function : + UTF8ToUnicode + + Convert a string from UTF-8 to UTF-16 (UCS-2) +--*/ +int UTF8ToUnicode(LPCSTR lpSrcStr, int cchSrc, LPWSTR lpDestStr, int cchDest, DWORD dwFlags); + + +/*++ +Function : + UnicodeToUTF8 + + Convert a string from UTF-16 (UCS-2) to UTF-8 +--*/ +int UnicodeToUTF8(LPCWSTR lpSrcStr, int cchSrc, LPSTR lpDestStr, int cchDest); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* _PAL_UTF8_H_ */ diff --git a/src/pal/src/include/pal/utils.h b/src/pal/src/include/pal/utils.h new file mode 100644 index 0000000000..3ddad4ae2f --- /dev/null +++ b/src/pal/src/include/pal/utils.h @@ -0,0 +1,157 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/utils.h + +Abstract: + Miscellaneous helper functions for the PAL, which don't fit anywhere else + + + +--*/ + +#ifndef _PAL_UTILS_H_ +#define _PAL_UTILS_H_ + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/*++ +Function: + UTIL_inverse_wcspbrk + + Opposite of wcspbrk : searches a string for the first character NOT in the + given set + +Parameters : + LPWSTR lpwstr : string to search + LPCWSTR charset : list of characters to search for + +Return value : + pointer to first character of lpwstr that isn't in the set + NULL if all characters are in the set +--*/ +LPWSTR UTIL_inverse_wcspbrk(LPWSTR lpwstr, LPCWSTR charset); + +/*++ +Function : + UTIL_IsReadOnlyBitsSet + + Takes a struct stat * + Returns true if the file is read only, +--*/ +BOOL UTIL_IsReadOnlyBitsSet( struct stat * stat_data ); + +/*++ +Function : + UTIL_IsExecuteBitsSet + + Takes a struct stat * + Returns true if the file is executable. +--*/ +BOOL UTIL_IsExecuteBitsSet( struct stat * stat_data ); + + +/*++ +Function : + UTIL_WCToMB_Alloc + + Converts a wide string to a multibyte string, allocating the required buffer + +Parameters : + LPCWSTR lpWideCharStr : string to convert + int cchWideChar : number of wide characters to convert + (-1 to convert a complete null-termnated string) + +Return Value : + newly allocated buffer containing the converted string. Conversion is + performed using CP_ACP. Buffer is allocated with malloc(), release it + with free(). + In case if failure, LastError will be set. +--*/ +LPSTR UTIL_WCToMB_Alloc(LPCWSTR lpWideCharStr, int cchWideChar); + +/*++ +Function : + UTIL_MBToWC_Alloc + + Converts a multibyte string to a wide string, allocating the required buffer + +Parameters : + LPCSTR lpMultiByteStr : string to convert + int cbMultiByte : number of bytes to convert + (-1 to convert a complete null-termnated string) + +Return Value : + newly allocated buffer containing the converted string. Conversion is + performed using CP_ACP. Buffer is allocated with malloc(), release it + with free(). + In case if failure, LastError will be set. +--*/ +LPWSTR UTIL_MBToWC_Alloc(LPCSTR lpMultiByteStr, int cbMultiByte); + +#if HAVE_VM_ALLOCATE +#include <mach/kern_return.h> + +/*++ +Function: + UTIL_MachErrorToPalError + + Maps a Mach kern_return_t to a Win32 error code. +--*/ +DWORD UTIL_MachErrorToPalError(kern_return_t MachReturn); + +/*++ +Function: + UTIL_SetLastErrorFromMach + + Sets Win32 LastError according to the argument Mach kern_return_t value, + provided it indicates an error. If the argument indicates success, does + not modify LastError. +--*/ +void UTIL_SetLastErrorFromMach(kern_return_t MachReturn); + +#endif //HAVE_VM_ALLOCATE + +#ifdef __cplusplus +} +#endif // __cplusplus +class StringHolder + { + private: + LPSTR data; + public: + StringHolder() : data(NULL) { } + ~StringHolder() + { + PAL_free( data); + } + + operator LPSTR () { return data;} + + StringHolder& operator= (LPSTR value) + { + data = value; + return *this; + } + + BOOL IsNull() + { + return data == NULL; + } + + }; +#endif /* _PAL_UTILS_H_ */ diff --git a/src/pal/src/include/pal/virtual.h b/src/pal/src/include/pal/virtual.h new file mode 100644 index 0000000000..a4e225281e --- /dev/null +++ b/src/pal/src/include/pal/virtual.h @@ -0,0 +1,208 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + include/pal/virtual.h + +Abstract: + Header file for virtual memory management. + + + +--*/ + +#ifndef _PAL_VIRTUAL_H_ +#define _PAL_VIRTUAL_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +typedef struct _CMI { + + struct _CMI * pNext; /* Link to the next entry. */ + struct _CMI * pPrevious; /* Link to the previous entry. */ + + UINT_PTR startBoundary; /* Starting location of the region. */ + SIZE_T memSize; /* Size of the entire region.. */ + + DWORD accessProtection; /* Initial allocation access protection. */ + DWORD allocationType; /* Initial allocation type. */ + + BYTE * pAllocState; /* Individual allocation type tracking for each */ + /* page in the region. */ + + BYTE * pProtectionState; /* Individual allocation type tracking for each */ + /* page in the region. */ + +} CMI, * PCMI; + +enum VIRTUAL_CONSTANTS +{ + /* Allocation type. */ + VIRTUAL_COMMIT_ALL_BITS = 0xFF, + VIRTUAL_RESERVE_ALL_BITS = 0x0, + + /* Protection Type. */ + VIRTUAL_READONLY, + VIRTUAL_READWRITE, + VIRTUAL_EXECUTE_READWRITE, + VIRTUAL_NOACCESS, + VIRTUAL_EXECUTE, + VIRTUAL_EXECUTE_READ, + + /* Page manipulation constants. */ +#ifdef __sparc__ + VIRTUAL_PAGE_SIZE = 0x2000, +#else // __sparc__ + VIRTUAL_PAGE_SIZE = 0x1000, +#endif // __sparc__ + VIRTUAL_PAGE_MASK = VIRTUAL_PAGE_SIZE - 1, + BOUNDARY_64K = 0xffff +}; + +/*++ +Function : + VIRTUALInitialize + + Initialize the critical sections. + +Return value: + TRUE if initialization succeeded + FALSE otherwise. +--*/ +BOOL VIRTUALInitialize(bool initializeExecutableMemoryAllocator); + +/*++ +Function : + VIRTUALCleanup + + Deletes the critical sections. + +--*/ +void VIRTUALCleanup( void ); + +#ifdef __cplusplus +} + +/*++ +Class: + ExecutableMemoryAllocator + + This class implements a virtual memory allocator for JIT'ed code. + The purpose of this allocator is to opportunistically reserve a chunk of virtual memory + that is located near the coreclr library (within 2GB range) that can be later used by + JIT. Having executable memory close to the coreclr library allows JIT to generate more + efficient code (by avoiding usage of jump stubs) and thus it can significantly improve + performance of the application. + + This allocator is integrated with the VirtualAlloc/Reserve code. If VirtualAlloc has been + called with the MEM_RESERVE_EXECUTABLE flag then it will first try to obtain the requested size + of virtual memory from ExecutableMemoryAllocator. If ExecutableMemoryAllocator runs out of + the reserved memory (or fails to allocate it during initialization) then VirtualAlloc/Reserve code + will simply fall back to reserving memory using OS APIs. + + Notes: + - the memory allocated by this class is NOT committed by default. It is responsibility + of the caller to commit the virtual memory before accessing it. + - in addition, this class does not provide ability to free the reserved memory. The caller + has full control of the memory it got from this allocator (i.e. the caller becomes + the owner of the allocated memory), so it is caller's responsibility to free the memory + if it is no longer needed. +--*/ +class ExecutableMemoryAllocator +{ +public: + /*++ + Function: + Initialize + + This function initializes the allocator. It should be called early during process startup + (when process address space is pretty much empty) in order to have a chance to reserve + sufficient amount of memory that is close to the coreclr library. + --*/ + void Initialize(); + + /*++ + Function: + AllocateMemory + + This function attempts to allocate the requested amount of memory from its reserved virtual + address space. The function will return NULL if the allocation request cannot + be satisfied by the memory that is currently available in the allocator. + --*/ + void* AllocateMemory(SIZE_T allocationSize); + +private: + /*++ + Function: + TryReserveInitialMemory + + This function is called during initialization. It opportunistically tries to reserve + a large chunk of virtual memory that can be later used to store JIT'ed code. + --*/ + void TryReserveInitialMemory(); + + /*++ + Function: + GenerateRandomStartOffset + + This function returns a random offset (in multiples of the virtual page size) + at which the allocator should start allocating memory from its reserved memory range. + --*/ + int32_t GenerateRandomStartOffset(); + +private: + // There does not seem to be an easy way find the size of a library on Unix. + // So this constant represents an approximation of the libcoreclr size (on debug build) + // that can be used to calculate an approximate location of the memory that + // is in 2GB range from the coreclr library. In addition, having precise size of libcoreclr + // is not necessary for the calculations. + const int32_t CoreClrLibrarySize = 100 * 1024 * 1024; + + // This constant represent the max size of the virtual memory that this allocator + // will try to reserve during initialization. We want all JIT-ed code and the + // entire libcoreclr to be located in a 2GB range. + const int32_t MaxExecutableMemorySize = 0x7FFF0000 - CoreClrLibrarySize; + + // Start address of the reserved virtual address space + void* m_startAddress; + + // Next available address in the reserved address space + void* m_nextFreeAddress; + + // Total size of the virtual memory that the allocator has been able to + // reserve during its initialization. + int32_t m_totalSizeOfReservedMemory; + + // Remaining size of the reserved virtual memory that can be used to satisfy allocation requests. + int32_t m_remainingReservedMemory; +}; + +#endif // __cplusplus + +/*++ +Function : + ReserveMemoryFromExecutableAllocator + + This function is used to reserve a region of virual memory (not commited) + that is located close to the coreclr library. The memory comes from the virtual + address range that is managed by ExecutableMemoryAllocator. +--*/ +void* ReserveMemoryFromExecutableAllocator(CorUnix::CPalThread* pthrCurrent, SIZE_T allocationSize); + +#endif /* _PAL_VIRTUAL_H_ */ + + + + + + + |