mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			256 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			256 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			C
		
	
	
	
| /* cilk_api.c                  -*-C-*-
 | |
|  *
 | |
|  *************************************************************************
 | |
|  *
 | |
|  *  @copyright
 | |
|  *  Copyright (C) 2009-2013, Intel Corporation
 | |
|  *  All rights reserved.
 | |
|  *  
 | |
|  *  @copyright
 | |
|  *  Redistribution and use in source and binary forms, with or without
 | |
|  *  modification, are permitted provided that the following conditions
 | |
|  *  are met:
 | |
|  *  
 | |
|  *    * Redistributions of source code must retain the above copyright
 | |
|  *      notice, this list of conditions and the following disclaimer.
 | |
|  *    * Redistributions in binary form must reproduce the above copyright
 | |
|  *      notice, this list of conditions and the following disclaimer in
 | |
|  *      the documentation and/or other materials provided with the
 | |
|  *      distribution.
 | |
|  *    * Neither the name of Intel Corporation nor the names of its
 | |
|  *      contributors may be used to endorse or promote products derived
 | |
|  *      from this software without specific prior written permission.
 | |
|  *  
 | |
|  *  @copyright
 | |
|  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | |
|  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | |
|  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | |
|  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | |
|  *  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | |
|  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | |
|  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 | |
|  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 | |
|  *  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | |
|  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
 | |
|  *  WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | |
|  *  POSSIBILITY OF SUCH DAMAGE.
 | |
|  **************************************************************************/
 | |
| 
 | |
| /*
 | |
|  * Implementation of functions declared in cilk_api.h
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Define the COMPILING_CILK_ABI_FUNCTIONS macro, so that
 | |
|  * compilation of this file generates non-inlined definitions for the
 | |
|  * functions marked as CILK_EXPORT_AND_INLINE in cilk_api.h.
 | |
|  *
 | |
|  * We must deal with these functions differently because we need to
 | |
|  * continue to ship nonlined versions of these functions.
 | |
|  *
 | |
|  *   CILK_EXPORT_AND_INLINE int __cilkrts_get_worker_rank(uint64_t *rank);
 | |
|  *   CILK_EXPORT_AND_INLINE int __cilkrts_bump_worker_rank();
 | |
|  *   CILK_EXPORT_AND_INLINE int __cilkrts_bump_loop_rank();
 | |
|  */
 | |
| #define COMPILING_CILK_API_FUNCTIONS
 | |
| 
 | |
| #include <internal/abi.h>
 | |
| #include <cilk/cilk_api.h>
 | |
| 
 | |
| #include "os.h"
 | |
| #include "os_mutex.h"
 | |
| #include "bug.h"
 | |
| #include "global_state.h"
 | |
| #include "local_state.h"
 | |
| #include "scheduler.h"
 | |
| #include "sysdep.h"
 | |
| 
 | |
| CILK_API_VOID __cilkrts_init(void)
 | |
| {
 | |
|     // Initialize, but don't start, the cilk runtime.
 | |
|     __cilkrts_init_internal(0);
 | |
| }
 | |
| 
 | |
| CILK_API_VOID __cilkrts_end_cilk(void)
 | |
| {
 | |
|     // Take out the global OS mutex while we do this to protect against
 | |
|     // another thread attempting to bind while we do this
 | |
|     global_os_mutex_lock();
 | |
| 
 | |
|     if (cilkg_is_published()) {
 | |
|         global_state_t *g = cilkg_get_global_state();
 | |
|         if (g->Q || __cilkrts_get_tls_worker())
 | |
|             __cilkrts_bug("Attempt to shut down Cilk while Cilk is still "
 | |
|                           "running");
 | |
|         __cilkrts_stop_workers(g);
 | |
|         __cilkrts_deinit_internal(g);
 | |
|     }
 | |
| 
 | |
|     global_os_mutex_unlock();
 | |
| }
 | |
| 
 | |
| CILK_API_INT
 | |
| __cilkrts_get_nworkers()
 | |
| {
 | |
|     return cilkg_get_nworkers();
 | |
| }
 | |
| 
 | |
| CILK_API_INT
 | |
| __cilkrts_get_total_workers()
 | |
| {
 | |
|     return cilkg_get_total_workers();
 | |
| }
 | |
| 
 | |
| CILK_API_INT __cilkrts_get_force_reduce(void)
 | |
| {
 | |
|     return cilkg_get_force_reduce();
 | |
| }
 | |
| 
 | |
| CILK_API_INT __cilkrts_set_param(const char* param, const char* value)
 | |
| {
 | |
|     return cilkg_set_param(param, value);
 | |
| }
 | |
| 
 | |
| #ifdef _WIN32
 | |
| CILK_API_INT __cilkrts_set_param_w(const wchar_t* param, const wchar_t* value)
 | |
| {
 | |
|     return cilkg_set_param_w(param, value);
 | |
| }
 | |
| #endif // _WIN32
 | |
| 
 | |
| /* Return a small integer indicating which Cilk worker the function is
 | |
|  * currently running on.  Each thread started by the Cilk runtime library
 | |
|  * (system worker) has a unique worker number in the range 1..P-1, where P is
 | |
|  * the valued returned by __cilkrts_get_nworkers().  All threads started by
 | |
|  * the user or by other libraries (user workers) share the worker number 0.
 | |
|  * Therefore, the worker number is not unique across multiple user threads.
 | |
|  *
 | |
|  * Implementor's note: The value returned from this function is different from
 | |
|  * the value, w->self, used in most debug messages.
 | |
|  */
 | |
| CILK_API_INT
 | |
| __cilkrts_get_worker_number(void)
 | |
| {
 | |
|     __cilkrts_worker *w = __cilkrts_get_tls_worker();
 | |
| 
 | |
|     if (0 == w)
 | |
|         /* A non-worker always has a worker number of zero. */
 | |
|         return 0;
 | |
|     else if (WORKER_USER == w->l->type)
 | |
|         /* User worker was once a non-worker, so its number should still be
 | |
|          * zero. */
 | |
|         return 0;
 | |
|     else
 | |
|         /* w->self for a system worker is in range 0..(P-1); adjust to 1..P
 | |
|          * to avoid conflicting with the user thread's worker number. */
 | |
|         return w->self + 1;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Internal definition of the pedigree context.  The size of the
 | |
|  * structure must match __cilkrts_pedigree_context_t defined in abi.i
 | |
|  */
 | |
| typedef struct pedigree_context_t
 | |
| {
 | |
|     /** Size of the structure, in bytes */
 | |
|     size_t size;
 | |
| 
 | |
|     /** Next __cilkrts_pedigree to return */
 | |
|     const __cilkrts_pedigree *pedigree;
 | |
| 
 | |
|     /** Unused.  Left over from previous implementation */
 | |
|     void *unused1;
 | |
| 
 | |
|     /** Unused.  Left over from previous implementation */
 | |
|     void *unused2;
 | |
| 
 | |
|     // // Debugging aid for pedigree-test:
 | |
|     // __cilkrts_stack_frame *expected_sf;
 | |
| } pedigree_context_t;
 | |
| 
 | |
| /*
 | |
|  * __cilkrts_get_pedigree_info
 | |
|  *
 | |
|  * Fetch the birthrank for a stack frame.  To initialize the walk, both sf_in
 | |
|  * and frame_in should be NULL.  parent_sf_ptr and parent_frame_ptr provide
 | |
|  * context for the stackwalk and should be returned as sf_in and frame_in on
 | |
|  * the next call.
 | |
|  *
 | |
|  * Returns:
 | |
|  *   0 - Success - birthrank, parent_sf_out and parent_frame_out are valid
 | |
|  *   >1 - Pedigree walk completed
 | |
|  *   <1 - Failure - -1: No worker bound to thread, -2: Sanity check failed
 | |
|  */
 | |
| 
 | |
| #define PEDIGREE_WALK_COMPLETE (__cilkrts_pedigree *)-1
 | |
| 
 | |
| CILK_API_INT
 | |
| __cilkrts_get_pedigree_info(__cilkrts_pedigree_context_t *external_context,
 | |
|                             uint64_t *sf_birthrank)
 | |
| {
 | |
|     pedigree_context_t *context = (pedigree_context_t *)external_context;
 | |
| 
 | |
|     CILK_ASSERT(sizeof(__cilkrts_pedigree_context_t) ==
 | |
|                 sizeof(pedigree_context_t));
 | |
|     if (context->size != sizeof(pedigree_context_t))
 | |
|         return -3;  // Invalid size
 | |
| 
 | |
|     // If the pointer to the last __cilkrts_pedigree is -1, we've
 | |
|     // finished the walk.  We're still done.
 | |
|     if (PEDIGREE_WALK_COMPLETE == context->pedigree)
 | |
|         return 1;
 | |
| 
 | |
|     // The passed in context value contains a pointer to the last
 | |
|     // __cilkrts_pedigree returned, or NULL if we're starting a
 | |
|     // new walk
 | |
|     if (NULL == context->pedigree)
 | |
|     {
 | |
|         __cilkrts_worker *w = __cilkrts_get_tls_worker();
 | |
| 	__cilkrts_pedigree* pedigree_node;
 | |
|         if (NULL != w) {
 | |
| 	    pedigree_node = &w->pedigree;
 | |
| 	}
 | |
| 	else {
 | |
| 	    pedigree_node = __cilkrts_get_tls_pedigree_leaf(1);
 | |
| 	}
 | |
| 	context->pedigree = pedigree_node->parent;
 | |
|     }
 | |
|     else
 | |
|         context->pedigree = context->pedigree->parent;
 | |
| 
 | |
|     // Note: If we want to omit the user root node,
 | |
|     // stop at context->pedigree->parent instead.
 | |
|     if (NULL == context->pedigree)
 | |
|     {
 | |
| 	context->pedigree = PEDIGREE_WALK_COMPLETE;
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     *sf_birthrank = context->pedigree->rank;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| CILK_API_PEDIGREE
 | |
| __cilkrts_get_pedigree_internal(__cilkrts_worker *w)
 | |
| {
 | |
|     if (NULL != w) {
 | |
| 	return w->pedigree;
 | |
|     }
 | |
|     else {
 | |
| 	const __cilkrts_pedigree *pedigree =
 | |
|             __cilkrts_get_tls_pedigree_leaf(1);
 | |
| 	return *pedigree;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| CILK_API_INT __cilkrts_bump_worker_rank_internal(__cilkrts_worker *w)
 | |
| {
 | |
|     __cilkrts_pedigree *pedigree;
 | |
|     pedigree = (w ? &w->pedigree : __cilkrts_get_tls_pedigree_leaf(1));
 | |
|     pedigree->rank++;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /* End cilk_api.c */
 |