1 /** 2 * Copyright (C) Mellanox Technologies Ltd. 2001-2017. ALL RIGHTS RESERVED. 3 * 4 * See file LICENSE for terms. 5 */ 6 7 8 #ifndef UCM_UTIL_REPLACE_H_ 9 #define UCM_UTIL_REPLACE_H_ 10 11 #include <ucm/bistro/bistro.h> 12 #include <ucs/datastruct/list.h> 13 #include <ucs/type/status.h> 14 #include <pthread.h> 15 16 extern pthread_mutex_t ucm_reloc_get_orig_lock; 17 extern pthread_t volatile ucm_reloc_get_orig_thread; 18 19 /** 20 * Define a replacement function to a memory-mapping function call, which calls 21 * the event handler, and if event handler returns error code - calls the original 22 * function. 23 */ 24 25 /* Due to CUDA API redifinition we have to create proxy macro to eliminate 26 * redifinition of internal finction names */ 27 #define UCM_DEFINE_REPLACE_FUNC(_name, _rettype, _fail_val, ...) \ 28 _UCM_DEFINE_REPLACE_FUNC(ucm_override_##_name, ucm_##_name, _rettype, _fail_val, __VA_ARGS__) 29 30 #define _UCM_DEFINE_REPLACE_FUNC(_over_name, _ucm_name, _rettype, _fail_val, ...) \ 31 \ 32 /* Define a symbol which goes to the replacement - in case we are loaded first */ \ 33 _rettype _over_name(UCM_FUNC_DEFINE_ARGS(__VA_ARGS__)) \ 34 { \ 35 _rettype res; \ 36 UCM_BISTRO_PROLOGUE; \ 37 ucm_trace("%s()", __FUNCTION__); \ 38 \ 39 if (ucs_unlikely(ucm_reloc_get_orig_thread == pthread_self())) { \ 40 return (_rettype)_fail_val; \ 41 } \ 42 res = _ucm_name(UCM_FUNC_PASS_ARGS(__VA_ARGS__)); \ 43 UCM_BISTRO_EPILOGUE; \ 44 return res; \ 45 } 46 47 #define UCM_OVERRIDE_FUNC(_name, _rettype) \ 48 _rettype _name() __attribute__ ((alias (UCS_PP_QUOTE(ucm_override_##_name)))); \ 49 50 #define UCM_DEFINE_DLSYM_FUNC(_name, _rettype, _fail_val, ...) \ 51 _UCM_DEFINE_DLSYM_FUNC(_name, ucm_orig_##_name, ucm_override_##_name, \ 52 _rettype, _fail_val, __VA_ARGS__) 53 54 #define _UCM_DEFINE_DLSYM_FUNC(_name, _orig_name, _over_name, _rettype, _fail_val, ...) \ 55 _rettype _over_name(UCM_FUNC_DEFINE_ARGS(__VA_ARGS__)); \ 56 \ 57 /* Call the original function using dlsym(RTLD_NEXT) */ \ 58 _rettype _orig_name(UCM_FUNC_DEFINE_ARGS(__VA_ARGS__)) \ 59 { \ 60 typedef _rettype (*func_ptr_t) (__VA_ARGS__); \ 61 static func_ptr_t orig_func_ptr = NULL; \ 62 \ 63 ucm_trace("%s()", __FUNCTION__); \ 64 \ 65 if (ucs_unlikely(orig_func_ptr == NULL)) { \ 66 pthread_mutex_lock(&ucm_reloc_get_orig_lock); \ 67 ucm_reloc_get_orig_thread = pthread_self(); \ 68 orig_func_ptr = (func_ptr_t)ucm_reloc_get_orig(UCS_PP_QUOTE(_name), \ 69 _over_name); \ 70 ucm_reloc_get_orig_thread = (pthread_t)-1; \ 71 pthread_mutex_unlock(&ucm_reloc_get_orig_lock); \ 72 } \ 73 return orig_func_ptr(UCM_FUNC_PASS_ARGS(__VA_ARGS__)); \ 74 } 75 76 #define UCM_DEFINE_REPLACE_DLSYM_FUNC(_name, _rettype, _fail_val, ...) \ 77 _UCM_DEFINE_DLSYM_FUNC(_name, ucm_orig_##_name, ucm_override_##_name, \ 78 _rettype, _fail_val, __VA_ARGS__) \ 79 _UCM_DEFINE_REPLACE_FUNC(ucm_override_##_name, ucm_##_name, \ 80 _rettype, _fail_val, __VA_ARGS__) 81 82 #define UCM_DEFINE_SYSCALL_FUNC(_name, _rettype, _syscall_id, ...) \ 83 /* Call syscall */ \ 84 _rettype ucm_orig_##_name(UCM_FUNC_DEFINE_ARGS(__VA_ARGS__)) \ 85 { \ 86 return (_rettype)syscall(_syscall_id, UCM_FUNC_PASS_ARGS(__VA_ARGS__)); \ 87 } 88 89 #if UCM_BISTRO_HOOKS 90 # define UCM_DEFINE_SELECT_FUNC(_name, _rettype, _fail_val, _syscall_id, ...) \ 91 _UCM_DEFINE_DLSYM_FUNC(_name, ucm_orig_##_name##_dlsym, ucm_override_##_name, \ 92 _rettype, _fail_val, __VA_ARGS__) \ 93 UCM_DEFINE_SYSCALL_FUNC(_name##_syscall, _rettype, _syscall_id, __VA_ARGS__) \ 94 _rettype ucm_orig_##_name(UCM_FUNC_DEFINE_ARGS(__VA_ARGS__)) \ 95 { \ 96 return (ucm_mmap_hook_mode() == UCM_MMAP_HOOK_BISTRO) ? \ 97 ucm_orig_##_name##_syscall(UCM_FUNC_PASS_ARGS(__VA_ARGS__)) : \ 98 ucm_orig_##_name##_dlsym(UCM_FUNC_PASS_ARGS(__VA_ARGS__)); \ 99 } 100 #else 101 # define UCM_DEFINE_SELECT_FUNC(_name, _rettype, _fail_val, _syscall_id, ...) \ 102 UCM_DEFINE_DLSYM_FUNC(_name, _rettype, _fail_val, __VA_ARGS__) 103 #endif 104 105 /* 106 * Define argument list with given types. 107 */ 108 #define UCM_FUNC_DEFINE_ARGS(...) \ 109 UCS_PP_FOREACH_SEP(_UCM_FUNC_ARG_DEFINE, _, \ 110 UCS_PP_ZIP((UCS_PP_SEQ(UCS_PP_NUM_ARGS(__VA_ARGS__))), \ 111 (__VA_ARGS__))) 112 113 /* 114 * Pass auto-generated arguments to a function call. 115 */ 116 #define UCM_FUNC_PASS_ARGS(...) \ 117 UCS_PP_FOREACH_SEP(_UCM_FUNC_ARG_PASS, _, UCS_PP_SEQ(UCS_PP_NUM_ARGS(__VA_ARGS__))) 118 119 120 /* 121 * Helpers 122 */ 123 #define _UCM_FUNC_ARG_DEFINE(_, _bundle) \ 124 __UCM_FUNC_ARG_DEFINE(_, UCS_PP_TUPLE_0 _bundle, UCS_PP_TUPLE_1 _bundle) 125 #define __UCM_FUNC_ARG_DEFINE(_, _index, _type) \ 126 _type UCS_PP_TOKENPASTE(arg, _index) 127 #define _UCM_FUNC_ARG_PASS(_, _index) \ 128 UCS_PP_TOKENPASTE(arg, _index) 129 130 #endif 131