/* $Source: bitbucket.org:berkeleylab/gasnet.git/gasnet_legacy.c $ * Description: GASNet-1 legacy API support layer * Copyright 2018, The Regents of the University of California. * Terms of use are as specified in license.txt */ #include #include // remove safety checks that protect the g2ex data elsewhere #undef gasneti_thunk_client #undef gasneti_thunk_endpoint #undef gasneti_thunk_tm #undef gasneti_thunk_segment gex_Client_t gasneti_thunk_client = NULL; gex_EP_t gasneti_thunk_endpoint = NULL; gex_TM_t gasneti_thunk_tm = NULL; gex_Segment_t gasneti_thunk_segment = NULL; // conduits may override this to relocate the legacy handlers // Note that legacy handlers are registered conditionally on the use of gasnet_attach or GEX_FLAG_USES_GASNET1 #ifndef GASNETI_LEGACY_HANDLER_BASE #define GASNETI_LEGACY_HANDLER_BASE 95 #endif #define _hidx_gasneti_legacy_memset_reqreph (GASNETI_LEGACY_HANDLER_BASE+0) static gex_AM_Entry_t *gasneti_legacy_handlers; static int gasneti_legacy_handlers_registered = 0; /* ------------------------------------------------------------------------------------ */ extern void gasneti_legacy_alloc_tm_hook(gasneti_TM_t _tm) { if (_tm->_flags & GEX_FLAG_USES_GASNET1) { gex_TM_t tm = gasneti_export_tm(_tm); gex_Client_t client = gex_TM_QueryClient(tm); if (gasneti_thunk_client && gasneti_thunk_client != client) { const char *name = gex_Client_QueryName(gasneti_thunk_client); if (gex_Client_QueryFlags(gasneti_thunk_client) & GASNETI_FLAG_INIT_LEGACY) name = "Legacy gasnet_init() call"; gasneti_fatalerror("%s: Only one client per process may use GASNet-1 APIs, and this was already claimed by <%s>", gex_Client_QueryName(client), name); } // save the GEX objects for use by g2ex, and mark them as used by g2ex gasneti_thunk_tm = tm; gasneti_thunk_client = client; gasneti_import_client(client)->_flags |= GEX_FLAG_USES_GASNET1; gasneti_thunk_endpoint = gex_TM_QueryEP(tm); gasneti_import_ep(gasneti_thunk_endpoint)->_flags |= GEX_FLAG_USES_GASNET1; if (!gasneti_legacy_handlers_registered) { int len = 0; int numreg = 0; while (gasneti_legacy_handlers[len].gex_fnptr) len++; /* calc len */ if (gasneti_amregister(gasneti_import_ep(gasneti_thunk_endpoint), gasneti_legacy_handlers, len, GASNETI_LEGACY_HANDLER_BASE, GASNETI_CLIENT_HANDLER_BASE, 0, &numreg) != GASNET_OK) gasneti_fatalerror("Error registering g2ex legacy AM handlers"); gasneti_assert(numreg == len); gasneti_legacy_handlers_registered = 1; } } } extern void gasneti_legacy_attach_checks(int checksegment) { gasneti_assert(gasneti_thunk_tm); gasneti_assert(gasneti_thunk_endpoint); gasneti_assert(gasneti_thunk_client); if (checksegment) { gasneti_assert(gasneti_thunk_segment); gasneti_assert(gex_Segment_QueryFlags(gasneti_thunk_segment) & GEX_FLAG_USES_GASNET1); gasneti_assert(gex_Segment_QueryClient(gasneti_thunk_segment) == gasneti_thunk_client); } gasneti_assert(gex_TM_QueryFlags(gasneti_thunk_tm) & GEX_FLAG_USES_GASNET1); gasneti_assert(gex_TM_QueryEP(gasneti_thunk_tm) == gasneti_thunk_endpoint); gasneti_assert(gex_EP_QueryFlags(gasneti_thunk_endpoint) & GEX_FLAG_USES_GASNET1); gasneti_assert(gex_EP_QueryClient(gasneti_thunk_endpoint) == gasneti_thunk_client); gasneti_assert(gex_Client_QueryFlags(gasneti_thunk_client) & GEX_FLAG_USES_GASNET1); } extern void gasneti_legacy_segment_attach_hook(gasneti_EP_t ep) { if (ep == gasneti_import_ep(gasneti_thunk_endpoint)) { // We just attached a segment to the g2ex EP, set the g2ex thunk segment gasneti_assert(ep->_flags & GEX_FLAG_USES_GASNET1); ep->_segment->_flags |= GEX_FLAG_USES_GASNET1; gasneti_thunk_segment = gasneti_export_segment(ep->_segment); } } /* ------------------------------------------------------------------------------------ */ // Legacy gasnet_attach() extern int gasnetc_attach_primary(void); extern int gasneti_attach( gex_TM_t _tm, gasnet_handlerentry_t *table, int numentries, uintptr_t segsize) { GASNETI_TRACE_PRINTF(O,("gasnet_attach(table (%i entries), segsize=%"PRIuPTR")", numentries, segsize)); gasneti_TM_t tm = gasneti_import_tm_nonpair(_tm); gasneti_EP_t ep = tm->_ep; if (!gasneti_init_done) GASNETI_RETURN_ERRR(NOT_INIT, "GASNet attach called before init"); if (gasneti_attach_done) GASNETI_RETURN_ERRR(NOT_INIT, "GASNet already attached"); /* check argument sanity */ #if GASNET_SEGMENT_FAST || GASNET_SEGMENT_LARGE if ((segsize % GASNET_PAGESIZE) != 0) GASNETI_RETURN_ERRR(BAD_ARG, "segsize not page-aligned"); if (segsize > gasneti_MaxLocalSegmentSize) GASNETI_RETURN_ERRR(BAD_ARG, "segsize too large"); #else segsize = 0; #endif /* primary attach */ if (GASNET_OK != gasnetc_attach_primary()) GASNETI_RETURN_ERRR(RESOURCE,"Error in primary attach"); #if GASNET_SEGMENT_FAST || GASNET_SEGMENT_LARGE /* register client segment */ gex_Segment_t seg; // g2ex segment is automatically saved by a hook if (GASNET_OK != gasneti_segmentAttach(&seg, _tm, segsize, GASNETI_FLAG_INIT_LEGACY)) GASNETI_RETURN_ERRR(RESOURCE,"Error attaching segment"); #elif GASNETC_SEGMENT_ATTACH_HOOK gex_Segment_t seg = GEX_SEGMENT_INVALID; // Everything + hook #endif #if GASNETC_SEGMENT_ATTACH_HOOK if (GASNET_OK != gasnetc_segment_attach_hook(seg, _tm)) GASNETI_RETURN_ERRR(RESOURCE,"Error attaching segment (conduit hook)"); #endif /* register client handlers */ if (table && gasneti_amregister_legacy(ep, table, numentries) != GASNET_OK) GASNETI_RETURN_ERRR(RESOURCE,"Error registering handlers"); /* ensure everything is initialized across all nodes */ gasnet_barrier(0, GASNET_BARRIERFLAG_UNNAMED); return GASNET_OK; } /* ------------------------------------------------------------------------------------ */ // Legacy memset support GASNETI_INLINE(gasneti_legacy_memset_reqreph_inner) void gasneti_legacy_memset_reqreph_inner(gex_Token_t token, gex_AM_Arg_t val, void *nbytes_arg, void *dest, void *op) { size_t nbytes = (uintptr_t)nbytes_arg; if (dest && nbytes) { // Request: memset memset(dest, (int)(uint32_t)val, nbytes); gasneti_sync_writes(); gex_AM_ReplyShort(token, gasneti_handleridx(gasneti_legacy_memset_reqreph), 0, 0, PACK(0), PACK(0), PACK(op)); } else { // Reply: completion gasneti_assert(!val && !nbytes && !dest); gasneti_assert(op); if (gasneti_op_is_eop(op)) { gasneti_eop_t * eop = op; gasneti_eop_markdone(eop); } else { gasneti_iop_t * iop = op; gasneti_iop_markdone(iop, 1, 0); } } } SHORT_HANDLER(gasneti_legacy_memset_reqreph,4,7, (token, a0, UNPACK(a1), UNPACK(a2), UNPACK(a3) ), (token, a0, UNPACK2(a1, a2), UNPACK2(a3, a4), UNPACK2(a5, a6))); #define GASNETI_TRACE_MEMSET(node,dest,val,nbytes) do { \ GASNETI_TRACE_PRINTF(D,("GASNET_MEMSET: " GASNETI_RADDRFMT" val=%02x nbytes=%" PRIuPTR,\ GASNETI_RADDRSTR(gasneti_thunk_tm,(node),(dest)), (val), \ (uintptr_t)(nbytes))); \ } while(0) #define GASNETI_CHECKLOCAL_MEMSET(tm,node,dest,val,nbytes) do { \ void *mapped_dest = gasnete_mapped_at(tm,node,dest); \ if (mapped_dest) { \ memset(mapped_dest,val,nbytes); \ gasnete_loopbackput_memsync(); \ return 0; \ }} while(0) extern gex_Event_t gasneti_legacy_memset_nb(gex_Rank_t node, void *dest, int val, size_t nbytes GASNETI_THREAD_FARG) { GASNETI_TRACE_MEMSET(node,dest,val,nbytes); gasneti_assert_reason(gasneti_legacy_handlers_registered, "gasnet_memset*() calls require gasnet_attach() or gex_Client_Init(..., GEX_FLAG_USES_GASNET1)"); if_pf (!nbytes) return 0; gasneti_boundscheck(gasneti_thunk_tm,node,dest,nbytes); GASNETI_CHECKLOCAL_MEMSET(gasneti_thunk_tm,node,dest,val,nbytes); gasneti_eop_t *eop = gasneti_eop_create(GASNETI_THREAD_PASS_ALONE); gex_AM_RequestShort(gasneti_thunk_tm, node, gasneti_handleridx(gasneti_legacy_memset_reqreph), 0, (gex_AM_Arg_t)val, PACK(nbytes), PACK(dest), PACK(eop)); return gasneti_eop_to_event(eop); } extern int gasneti_legacy_memset_nbi(gex_Rank_t node, void *dest, int val, size_t nbytes GASNETI_THREAD_FARG) { GASNETI_TRACE_MEMSET(node,dest,val,nbytes); gasneti_assert_reason(gasneti_legacy_handlers_registered, "gasnet_memset*() calls require gasnet_attach() or gex_Client_Init(..., GEX_FLAG_USES_GASNET1)"); if_pf (!nbytes) return 0; gasneti_boundscheck(gasneti_thunk_tm,node,dest,nbytes); GASNETI_CHECKLOCAL_MEMSET(gasneti_thunk_tm,node,dest,val,nbytes); gasneti_iop_t *iop = gasneti_iop_register(1, 0 GASNETI_THREAD_PASS); gex_AM_RequestShort(gasneti_thunk_tm, node, gasneti_handleridx(gasneti_legacy_memset_reqreph), 0, (gex_AM_Arg_t)val, PACK(nbytes), PACK(dest), PACK(iop)); return 0; } static gex_AM_Entry_t _gasneti_legacy_handlers[] = { gasneti_handler_tableentry_with_bits(gasneti_legacy_memset_reqreph,4,7,REQREP,SHORT,0), GASNETI_HANDLER_EOT }; static gex_AM_Entry_t *gasneti_legacy_handlers = _gasneti_legacy_handlers;