From 5ee666a4b94e75d0a682b6acbc8c43fcc95d58ab Mon Sep 17 00:00:00 2001 From: Mark Seaborn Date: Sat, 21 Feb 2009 18:26:20 +0000 Subject: [PATCH] Add files that I missed when importing NaCl changes earlier --- gcc/config/i386/nacl.h | 75 +++++++ gcc/config/nacl.opt | 54 +++++ gcc/ctrl-intg.c | 351 +++++++++++++++++++++++++++++++ gcc/gthr-nacl.h | 553 +++++++++++++++++++++++++++++++++++++++++++++++++ stage_current | 1 + stage_final | 1 + stage_last | 1 + 7 files changed, 1036 insertions(+) create mode 100644 gcc/config/i386/nacl.h create mode 100644 gcc/config/nacl.opt create mode 100644 gcc/ctrl-intg.c create mode 100644 gcc/gthr-nacl.h create mode 100644 stage_current create mode 100644 stage_final create mode 100644 stage_last diff --git a/gcc/config/i386/nacl.h b/gcc/config/i386/nacl.h new file mode 100644 index 00000000000..00e8304500e --- /dev/null +++ b/gcc/config/i386/nacl.h @@ -0,0 +1,75 @@ +/* Target definitions for GCC for NativeClient using ELF + Copyright (C) 1988, 1991, 1995, 2000, 2001, 2002 + Free Software Foundation, Inc. + + Derived from sysv4.h written by Ron Guilmette (rfg@netcom.com). + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* These definitions modify those in i386elf.h. */ + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (NativeClient)"); + +/* Pass the NativeClient specific options to the assembler */ +#undef ASM_SPEC +#define ASM_SPEC \ + "%{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} " \ + "%{fnacl-library-mode:-nacl-library-mode} " \ + "%{fnacl-align-16:-nacl-align=4} " \ + "%{fnacl-align-32:-nacl-align=5} " \ + "%{Ym,*} %{Yd,*} %{Wa,*:%*}" + +#undef LIB_SPEC +#define LIB_SPEC \ + "%{pthread:-lpthread} \ + %{shared:-lc} \ + %{!shared:%{mieee-fp:-lieee} %{profile:-lc_p}%{!profile:-lc}} -lnacl -lsrpc" + +/* + * Set the linker emulation to be elf_nacl rather than linux.h's default + * (elf_i386). + */ +#ifdef LINK_EMULATION +#undef LINK_EMULATION +#endif +#define LINK_EMULATION "elf_nacl" + +/* + * Because of NaCl's use of segment registers, negative offsets from gs: will + * not work. Hence we need to make TLS references explicitly compute the + * tls base pointer and then indirect relative to it using the default + * segment descriptor (DS). That is, instead of + * movl gs:i@NTPOFF, %ecx + * we use + * movl %gs:0, %eax + * movl i@NTPOFF(%eax), %ecx + * There is a slight performance penalty for TLS accesses, but there does not + * seem a way around it. + */ +#undef TARGET_TLS_DIRECT_SEG_REFS_DEFAULT +#define TARGET_TLS_DIRECT_SEG_REFS_DEFAULT 0 + +#undef TARGET_OS_CPP_BUILTINS +#define TARGET_OS_CPP_BUILTINS() \ + do \ + { \ + LINUX_TARGET_OS_CPP_BUILTINS(); \ + builtin_define ("__native_client__=1"); \ + } \ + while (0) diff --git a/gcc/config/nacl.opt b/gcc/config/nacl.opt new file mode 100644 index 00000000000..ef9616dd797 --- /dev/null +++ b/gcc/config/nacl.opt @@ -0,0 +1,54 @@ +; Processor-independent options for GNU/Linux. +; +; Copyright (C) 2006, 2007 Free Software Foundation, Inc. +; Contributed by Google +; +; This file is part of GCC. +; +; GCC is free software; you can redistribute it and/or modify it under +; the terms of the GNU General Public License as published by the Free +; Software Foundation; either version 3, or (at your option) any later +; version. +; +; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +; WARRANTY; without even the implied warranty of MERCHANTABILITY or +; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +; for more details. +; +; You should have received a copy of the GNU General Public License +; along with GCC; see the file COPYING3. If not see +; . + +fcontrol-integrity +Common Report Var(flag_control_integrity) Init(1) +Expand indirect call, jmp, and rets + +falign-functions +Common Report Var(align_functions,NACL_ALIGN_BYTES) Init(NACL_ALIGN_BYTES) +Align the start of functions + +falign-functions= +Common RejectNegative Joined UInteger + +falign-jumps +Common Report Var(align_jumps,NACL_ALIGN_BYTES) Init(NACL_ALIGN_BYTES) +Align labels which are only reached by jumping + +falign-jumps= +Common RejectNegative Joined UInteger + +falign-labels +Common Report Var(align_labels,NACL_ALIGN_BYTES) Init(NACL_ALIGN_BYTES) +Align all labels + +falign-labels= +Common RejectNegative Joined UInteger + +fnacl-library-mode +Common Report Var(flag_nacl_library_mode,1) Init(0) + +fnacl-align-16 +Common Report Var(flag_nacl_align_pow2,4) Init(NACL_ALIGN_POW2) + +fnacl-align-32 +Common Report Var(flag_nacl_align_pow2,5) diff --git a/gcc/ctrl-intg.c b/gcc/ctrl-intg.c new file mode 100644 index 00000000000..b2f5a9aac93 --- /dev/null +++ b/gcc/ctrl-intg.c @@ -0,0 +1,351 @@ +/* Patch RTL to enforce control flow integrity for GCC. + Copyright (C) 1987, 1988, 1992, 1997, 1998, 1999, 2000, 2002, 2003, + 2004, 2005, 2007 + Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +/* This file is compiled twice: once for the generator programs, + once for the compiler. */ +#ifdef GENERATOR_FILE +#include "bconfig.h" +#else +#include "config.h" +#endif + +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "tree-pass.h" +#include "expr.h" + +/* These headers all define things which are not available in + generator programs. */ +#ifndef GENERATOR_FILE +#include "tree.h" +#include "real.h" +#include "flags.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#endif + +static bool +gate_func (void) { + return getenv("NACLSHUTDOWN") == NULL; + // return flag_control_integrity; +} + +static void +process_call_insn(rtx insn) { + rtx return_value_expr, call_expr, mem_expr, addr_expr, parallel_expr; + rtx sp_size_expr; + + /* + * Get the expression to be examined from the instruction. + */ + call_expr = XEXP (insn, 5); + + if (GET_CODE (call_expr) == PARALLEL) { + /* + * Calls that pop the stack use a PARALLEL containing a CALL and a SET. + */ + parallel_expr = call_expr; + sp_size_expr = XEXP (XEXP (XVECEXP (call_expr, 0, 1), 1), 1); + call_expr = XVECEXP (call_expr, 0, 0); + } + else { + parallel_expr = NULL_RTX; + } + + /* + * Get the call expression and return value (if any). + */ + if (GET_CODE (call_expr) == SET) { + /* + * Functions with return values use a SET instruction wrapper. + * Get the call out of the set if needed. + */ + return_value_expr = XEXP (call_expr, 0); + call_expr = XEXP (call_expr, 1); + } + else { + return_value_expr = NULL_RTX; + } + + /* + * Extract the target address expression of the function. + */ + mem_expr = XEXP (call_expr, 0); + + /* + * Get the address expression from the MEM. + */ + + gcc_assert (GET_CODE (mem_expr) == MEM); + addr_expr = XEXP (mem_expr, 0); + + if (GET_CODE (addr_expr) != SYMBOL_REF) { + rtx insns_head, call, call_insn; + int enable_print; + + { + static int calls_converted=0; + static int printed=0; + char* call_limit = getenv("NONACLCALL"); + char* name_compare = getenv("NACLBINS"); + if (name_compare && strcmp(main_input_filename, name_compare) > 0) { + if (printed == 0) { + fprintf(stderr, "NACL: name test shut off\n"); + printed = 1; + } + return; + } + + ++calls_converted; + enable_print = (call_limit && calls_converted == atoi(call_limit)); + if (call_limit && calls_converted > atoi(call_limit)) { + if (printed == 0) { + fprintf(stderr, "NACL: '%s' call limit exceeded\n", + main_input_filename); + printed = 1; + } + return; + } + /* fprintf(stderr, "NACL: converted call %d\n", calls_converted); */ + } + + /* DCS -- debugging code */ + if (return_value_expr && parallel_expr) { + if (getenv("NACLDBGBOTH")) return; + } else if (return_value_expr) { + if (getenv("NACLDBGRET")) return; + } else if (parallel_expr) { + if (getenv("NACLDBGPAR")) return; + } else { + if (SIBLING_CALL_P (insn)) { + if (getenv("NACLDBGNONE1")) return; + } else { + char* str = getenv("NACLDBGNONE2"); + if (str) { + FILE* fp = fopen("/home/sehr/NACLDBGCOUNT", "r+"); + int current_count; + fscanf(fp, "%d\n", ¤t_count); + fprintf(stderr, "NACLDEBUGCOUNT = %d \n", current_count); + rewind(fp); + fprintf(fp, "%d\n", current_count+1); + fclose(fp); + if (current_count > atoi(str)) { + fprintf(stderr, "NACLDEBUGCOUNT %d exceeded %d\n", + current_count, atoi(str)); + return; + } + } + } + } + + start_sequence (); + + if (enable_print) { + fprintf(stderr, "Before:\n"); + print_rtl_single(stderr, insn); + } + + /* + * Force the called function address to be in a register. + */ + addr_expr = force_reg (GET_MODE (addr_expr), addr_expr); + + /* + * Generate the appropriate template for the call + */ + if (return_value_expr && parallel_expr) { + call = gen_naclcall_value_pop (return_value_expr, addr_expr, + XEXP (call_expr, 1), sp_size_expr); + } else if (return_value_expr) { + if (SIBLING_CALL_P (insn)) { + call = gen_naclsibcall_value (return_value_expr, + addr_expr, XEXP (call_expr, 1)); + } else { + call = gen_naclcall_value (return_value_expr, + addr_expr, XEXP (call_expr, 1)); + } + } else if (parallel_expr) { + call = gen_naclcall_pop (addr_expr, XEXP (call_expr, 1), + sp_size_expr); + } else { + if (SIBLING_CALL_P (insn)) { + call = gen_naclsibcall (addr_expr, XEXP (call_expr, 1)); + } else { + call = gen_naclcall (addr_expr, XEXP (call_expr, 1)); + } + } + + call_insn = emit_call_insn (call); + + CONST_OR_PURE_CALL_P (call_insn) = CONST_OR_PURE_CALL_P (insn); + SIBLING_CALL_P (call_insn) = SIBLING_CALL_P (insn); + + insns_head = get_insns (); + + if (enable_print) { + fprintf(stderr, "After: (%d, %d) \n", CONST_OR_PURE_CALL_P (call_insn), + SIBLING_CALL_P (call_insn)); + print_rtl(stderr, insns_head); + } + + end_sequence (); + emit_insn_before (insns_head, insn); + + delete_insn (insn); + } +} + + +static void +process_jump_insn(rtx insn) { + rtx par_expr, set_expr, addr_expr; + rtx jmp; + + /* + * Get the contained expression. + */ + par_expr = XEXP (insn, 5); + + if (GET_CODE (par_expr) == PARALLEL) { + set_expr = XVECEXP (par_expr, 0, 0); + + if (GET_CODE (set_expr) == SET) { + addr_expr = XEXP (set_expr, 1); + + if (GET_CODE (addr_expr) == IF_THEN_ELSE) { + /* + * Ordinary branches uses parallel/set/if_then_else. + * Leave them unmodified. + */ + } + else { + /* + * A table indirect jump instruction has parallel/set/other + */ + rtx insns_head, jmp_insn; + int enable_print; + + { + static int calls_converted=0; + static int printed=0; + char* name_compare = getenv("NACLBINS"); + char* call_limit = getenv("NONACLJMP"); + if (name_compare && strcmp(main_input_filename, name_compare) > 0) { + fprintf(stderr, "NACL: name test shut off\n"); + return; + } + + ++calls_converted; + enable_print = (call_limit && calls_converted == atoi(call_limit)); + if (call_limit && calls_converted > atoi(call_limit)) { + if (printed == 0) { + fprintf(stderr, "NACL: '%s' call limit exceeded\n", + main_input_filename); + printed = 1; + } + return; + } + /*fprintf(stderr, "NACL: converted branch %d\n", calls_converted);*/ + } + + start_sequence (); + + if (enable_print) { + fprintf(stderr, "Before:\n"); + print_rtl_single(stderr, insn); + } + addr_expr = force_reg (GET_MODE (addr_expr), addr_expr); + jmp = gen_nacljmp_table (addr_expr, + XEXP (XEXP (XVECEXP (par_expr, 0, 1), 0), 0)); + jmp_insn = emit_jump_insn (jmp); + + if (JUMP_LABEL (insn) != NULL_RTX) { + JUMP_LABEL (jmp_insn) = JUMP_LABEL (insn); + LABEL_NUSES (JUMP_LABEL (insn))++; + } + + insns_head = get_insns (); + if (enable_print) { + fprintf(stderr, "After %p:\n", (void*) JUMP_LABEL (jmp_insn)); + print_rtl(stderr, insns_head); + } + + end_sequence (); + emit_insn_before (insns_head, insn); + + delete_insn (insn); + } + } + } else { + /* + * Other indirect jumps remain to be identified. + */ + } +} + + +static int +execute_func (void) { + basic_block bb; + int save_nnp; + + if (getenv("NACLSHUTDOWN4")) return 0; + save_nnp = no_new_pseudos; + no_new_pseudos = 0; + FOR_EACH_BB (bb) { + rtx insn, last; + + if (getenv("NACLSHUTDOWN3")) continue; + for (insn = BB_HEAD (bb), last = NEXT_INSN (BB_END (bb)); insn != last; + insn = NEXT_INSN(insn)) { + if (getenv("NACLSHUTDOWN2")) continue; + if (JUMP_P (insn)) { + if (flag_control_integrity) + process_jump_insn (insn); + } + if (CALL_P (insn)) { + if (flag_control_integrity) + process_call_insn (insn); + } + } + } + + no_new_pseudos = save_nnp; + return 0; +} + +struct tree_opt_pass pass_control_integrity = { + "ctrl_intg_insert", + gate_func, + execute_func, + 0, /* sub */ + 0, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + TODO_dump_func, /* todo_flags_start */ + TODO_dump_func, /* todo_flags_finish */ + 'r' +}; diff --git a/gcc/gthr-nacl.h b/gcc/gthr-nacl.h new file mode 100644 index 00000000000..f99bedd52d8 --- /dev/null +++ b/gcc/gthr-nacl.h @@ -0,0 +1,553 @@ +/* Threads compatibility routines for libgcc2 and libobjc. */ +/* Compile this one with gcc. */ +/* Copyright (C) 1997, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#ifndef GCC_GTHR_POSIX_H +#define GCC_GTHR_POSIX_H + +/* POSIX threads specific definitions. + Easy, since the interface is just one-to-one mapping. */ + +#define __GTHREADS 1 + +/* Some implementations of require this to be defined. */ +#if !defined(_REENTRANT) && defined(__osf__) +#define _REENTRANT 1 +#endif + +#include +#include + +typedef pthread_key_t __gthread_key_t; +typedef pthread_once_t __gthread_once_t; +typedef pthread_mutex_t __gthread_mutex_t; +typedef pthread_mutex_t __gthread_recursive_mutex_t; + +#define __GTHREAD_MUTEX_INIT PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP +#define __GTHREAD_ONCE_INIT PTHREAD_ONCE_INIT +#define __GTHREAD_RECURSIVE_MUTEX_INIT PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP + +#if SUPPORTS_WEAK && GTHREAD_USE_WEAK +# ifndef __gthrw_pragma +# define __gthrw_pragma(pragma) +# endif +# define __gthrw2(name,name2,type) \ + static __typeof(type) name __attribute__ ((__weakref__(#name2))); \ + __gthrw_pragma(weak type) +# define __gthrw_(name) __gthrw_ ## name +#else +# define __gthrw2(name,name2,type) +# define __gthrw_(name) name +#endif + +/* Typically, __gthrw_foo is a weak reference to symbol foo. */ +#define __gthrw(name) __gthrw2(__gthrw_ ## name,name,name) + +__gthrw(pthread_once) +__gthrw(pthread_getspecific) +__gthrw(pthread_setspecific) +__gthrw(pthread_create) +__gthrw(pthread_mutex_lock) +__gthrw(pthread_mutex_trylock) +__gthrw(pthread_mutex_unlock) +__gthrw(pthread_mutex_init) + +__gthrw(pthread_key_create) +__gthrw(pthread_key_delete) + + +#if defined(_LIBOBJC) || defined(_LIBOBJC_WEAK) +/* Objective-C. */ +__gthrw(pthread_cond_broadcast) +__gthrw(pthread_cond_destroy) +__gthrw(pthread_cond_init) +__gthrw(pthread_cond_signal) +__gthrw(pthread_cond_wait) +__gthrw(pthread_exit) +__gthrw(pthread_mutex_destroy) +__gthrw(pthread_self) +#ifdef _POSIX_PRIORITY_SCHEDULING +#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING +__gthrw(sched_get_priority_max) +__gthrw(sched_get_priority_min) +#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */ +#endif /* _POSIX_PRIORITY_SCHEDULING */ +__gthrw(sched_yield) +__gthrw(pthread_attr_destroy) +__gthrw(pthread_attr_init) +__gthrw(pthread_attr_setdetachstate) +#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING +__gthrw(pthread_getschedparam) +__gthrw(pthread_setschedparam) +#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */ +#endif /* _LIBOBJC || _LIBOBJC_WEAK */ + +static inline int +__gthread_active_p (void) +{ + /* + * The threading library is active if a basic thread creation/destruction + * primitive is referenced. Unfortunately we don't have those yet. + * TODO: change to reference a thread creation/destruction function + * when one becomes available. + */ + static void *const __gthread_active_ptr + = __extension__ (void *) &__gthrw_(pthread_mutex_lock); + return __gthread_active_ptr != 0; +} + +#ifdef _LIBOBJC + +/* This is the config.h file in libobjc/ */ +#include + +#ifdef HAVE_SCHED_H +# include +#endif + +/* Key structure for maintaining thread specific storage */ +static pthread_key_t _objc_thread_storage; +static pthread_attr_t _objc_thread_attribs; + +/* Thread local storage for a single thread */ +static void *thread_local_storage = NULL; + +/* Backend initialization functions */ + +/* Initialize the threads subsystem. */ +static inline int +__gthread_objc_init_thread_system (void) +{ + if (__gthread_active_p ()) + { + /* Initialize the thread storage key. */ + if (__gthrw_(pthread_key_create) (&_objc_thread_storage, NULL) == 0) + { + /* The normal default detach state for threads is + * PTHREAD_CREATE_JOINABLE which causes threads to not die + * when you think they should. */ + if (__gthrw_(pthread_attr_init) (&_objc_thread_attribs) == 0 + && __gthrw_(pthread_attr_setdetachstate) (&_objc_thread_attribs, + PTHREAD_CREATE_DETACHED) == 0) + return 0; + } + } + + return -1; +} + +/* Close the threads subsystem. */ +static inline int +__gthread_objc_close_thread_system (void) +{ + if (__gthread_active_p () + && __gthrw_(pthread_key_delete) (_objc_thread_storage) == 0 + && __gthrw_(pthread_attr_destroy) (&_objc_thread_attribs) == 0) + return 0; + + return -1; +} + +/* Backend thread functions */ + +/* Create a new thread of execution. */ +static inline objc_thread_t +__gthread_objc_thread_detach (void (*func)(void *), void *arg) +{ + objc_thread_t thread_id; + pthread_t new_thread_handle; + + if (!__gthread_active_p ()) + return NULL; + + if (!(__gthrw_(pthread_create) (&new_thread_handle, NULL, (void *) func, arg))) + thread_id = (objc_thread_t) new_thread_handle; + else + thread_id = NULL; + + return thread_id; +} + +/* Set the current thread's priority. */ +static inline int +__gthread_objc_thread_set_priority (int priority) +{ + if (!__gthread_active_p ()) + return -1; + else + { +#ifdef _POSIX_PRIORITY_SCHEDULING +#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING + pthread_t thread_id = __gthrw_(pthread_self) (); + int policy; + struct sched_param params; + int priority_min, priority_max; + + if (__gthrw_(pthread_getschedparam) (thread_id, &policy, ¶ms) == 0) + { + if ((priority_max = __gthrw_(sched_get_priority_max) (policy)) == -1) + return -1; + + if ((priority_min = __gthrw_(sched_get_priority_min) (policy)) == -1) + return -1; + + if (priority > priority_max) + priority = priority_max; + else if (priority < priority_min) + priority = priority_min; + params.sched_priority = priority; + + /* + * The solaris 7 and several other man pages incorrectly state that + * this should be a pointer to policy but pthread.h is universally + * at odds with this. + */ + if (__gthrw_(pthread_setschedparam) (thread_id, policy, ¶ms) == 0) + return 0; + } +#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */ +#endif /* _POSIX_PRIORITY_SCHEDULING */ + return -1; + } +} + +/* Return the current thread's priority. */ +static inline int +__gthread_objc_thread_get_priority (void) +{ +#ifdef _POSIX_PRIORITY_SCHEDULING +#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING + if (__gthread_active_p ()) + { + int policy; + struct sched_param params; + + if (__gthrw_(pthread_getschedparam) (__gthrw_(pthread_self) (), &policy, ¶ms) == 0) + return params.sched_priority; + else + return -1; + } + else +#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */ +#endif /* _POSIX_PRIORITY_SCHEDULING */ + return OBJC_THREAD_INTERACTIVE_PRIORITY; +} + +/* Yield our process time to another thread. */ +static inline void +__gthread_objc_thread_yield (void) +{ + if (__gthread_active_p ()) + __gthrw_(sched_yield) (); +} + +/* Terminate the current thread. */ +static inline int +__gthread_objc_thread_exit (void) +{ + if (__gthread_active_p ()) + /* exit the thread */ + __gthrw_(pthread_exit) (&__objc_thread_exit_status); + + /* Failed if we reached here */ + return -1; +} + +/* Returns an integer value which uniquely describes a thread. */ +static inline objc_thread_t +__gthread_objc_thread_id (void) +{ + if (__gthread_active_p ()) + return (objc_thread_t) __gthrw_(pthread_self) (); + else + return (objc_thread_t) 1; +} + +/* Sets the thread's local storage pointer. */ +static inline int +__gthread_objc_thread_set_data (void *value) +{ + if (__gthread_active_p ()) + return __gthrw_(pthread_setspecific) (_objc_thread_storage, value); + else + { + thread_local_storage = value; + return 0; + } +} + +/* Returns the thread's local storage pointer. */ +static inline void * +__gthread_objc_thread_get_data (void) +{ + if (__gthread_active_p ()) + return __gthrw_(pthread_getspecific) (_objc_thread_storage); + else + return thread_local_storage; +} + +/* Backend mutex functions */ + +/* Allocate a mutex. */ +static inline int +__gthread_objc_mutex_allocate (objc_mutex_t mutex) +{ + if (__gthread_active_p ()) + { + mutex->backend = objc_malloc (sizeof (pthread_mutex_t)); + + if (__gthrw_(pthread_mutex_init) ((pthread_mutex_t *) mutex->backend, NULL)) + { + objc_free (mutex->backend); + mutex->backend = NULL; + return -1; + } + } + + return 0; +} + +/* Deallocate a mutex. */ +static inline int +__gthread_objc_mutex_deallocate (objc_mutex_t mutex) +{ + if (__gthread_active_p ()) + { + int count; + + /* + * Posix Threads specifically require that the thread be unlocked + * for __gthrw_(pthread_mutex_destroy) to work. + */ + + do + { + count = __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend); + if (count < 0) + return -1; + } + while (count); + + if (__gthrw_(pthread_mutex_destroy) ((pthread_mutex_t *) mutex->backend)) + return -1; + + objc_free (mutex->backend); + mutex->backend = NULL; + } + return 0; +} + +/* Grab a lock on a mutex. */ +static inline int +__gthread_objc_mutex_lock (objc_mutex_t mutex) +{ + if (__gthread_active_p () + && __gthrw_(pthread_mutex_lock) ((pthread_mutex_t *) mutex->backend) != 0) + { + return -1; + } + + return 0; +} + +/* Try to grab a lock on a mutex. */ +static inline int +__gthread_objc_mutex_trylock (objc_mutex_t mutex) +{ + if (__gthread_active_p () + && __gthrw_(pthread_mutex_trylock) ((pthread_mutex_t *) mutex->backend) != 0) + { + return -1; + } + + return 0; +} + +/* Unlock the mutex */ +static inline int +__gthread_objc_mutex_unlock (objc_mutex_t mutex) +{ + if (__gthread_active_p () + && __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend) != 0) + { + return -1; + } + + return 0; +} + +/* Backend condition mutex functions */ + +/* Allocate a condition. */ +static inline int +__gthread_objc_condition_allocate (objc_condition_t condition) +{ + if (__gthread_active_p ()) + { + condition->backend = objc_malloc (sizeof (pthread_cond_t)); + + if (__gthrw_(pthread_cond_init) ((pthread_cond_t *) condition->backend, NULL)) + { + objc_free (condition->backend); + condition->backend = NULL; + return -1; + } + } + + return 0; +} + +/* Deallocate a condition. */ +static inline int +__gthread_objc_condition_deallocate (objc_condition_t condition) +{ + if (__gthread_active_p ()) + { + if (__gthrw_(pthread_cond_destroy) ((pthread_cond_t *) condition->backend)) + return -1; + + objc_free (condition->backend); + condition->backend = NULL; + } + return 0; +} + +/* Wait on the condition */ +static inline int +__gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex) +{ + if (__gthread_active_p ()) + return __gthrw_(pthread_cond_wait) ((pthread_cond_t *) condition->backend, + (pthread_mutex_t *) mutex->backend); + else + return 0; +} + +/* Wake up all threads waiting on this condition. */ +static inline int +__gthread_objc_condition_broadcast (objc_condition_t condition) +{ + if (__gthread_active_p ()) + return __gthrw_(pthread_cond_broadcast) ((pthread_cond_t *) condition->backend); + else + return 0; +} + +/* Wake up one thread waiting on this condition. */ +static inline int +__gthread_objc_condition_signal (objc_condition_t condition) +{ + if (__gthread_active_p ()) + return __gthrw_(pthread_cond_signal) ((pthread_cond_t *) condition->backend); + else + return 0; +} + +#else /* _LIBOBJC */ + +static inline int +__gthread_once (__gthread_once_t *once, void (*func) (void)) +{ + if (__gthread_active_p ()) + return __gthrw_(pthread_once) (once, func); + else + return -1; +} + +static inline int +__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *)) +{ + return __gthrw_(pthread_key_create) (key, dtor); +} + +static inline int +__gthread_key_delete (__gthread_key_t key) +{ + return __gthrw_(pthread_key_delete) (key); +} + +static inline void * +__gthread_getspecific (__gthread_key_t key) +{ + return __gthrw_(pthread_getspecific) (key); +} + +static inline int +__gthread_setspecific (__gthread_key_t key, const void *ptr) +{ + return __gthrw_(pthread_setspecific) (key, ptr); +} + +static inline int +__gthread_mutex_lock (__gthread_mutex_t *mutex) +{ + if (__gthread_active_p ()) + return __gthrw_(pthread_mutex_lock) (mutex); + else + return 0; +} + +static inline int +__gthread_mutex_trylock (__gthread_mutex_t *mutex) +{ + if (__gthread_active_p ()) + return __gthrw_(pthread_mutex_trylock) (mutex); + else + return 0; +} + +static inline int +__gthread_mutex_unlock (__gthread_mutex_t *mutex) +{ + if (__gthread_active_p ()) + return __gthrw_(pthread_mutex_unlock) (mutex); + else + return 0; +} + +static inline int +__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex) +{ + return __gthread_mutex_lock (mutex); +} + +static inline int +__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex) +{ + return __gthread_mutex_trylock (mutex); +} + +static inline int +__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex) +{ + return __gthread_mutex_unlock (mutex); +} + +#endif /* _LIBOBJC */ + +#endif /* ! GCC_GTHR_POSIX_H */ diff --git a/stage_current b/stage_current new file mode 100644 index 00000000000..a972fee4fb7 --- /dev/null +++ b/stage_current @@ -0,0 +1 @@ +stage1 diff --git a/stage_final b/stage_final new file mode 100644 index 00000000000..92f251d7e7c --- /dev/null +++ b/stage_final @@ -0,0 +1 @@ +stage3 diff --git a/stage_last b/stage_last new file mode 100644 index 00000000000..a972fee4fb7 --- /dev/null +++ b/stage_last @@ -0,0 +1 @@ +stage1 -- 2.11.4.GIT