1 // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3 // 4 // SPDX-License-Identifier: BSD-2-Clause 5 // 6 // This file is part of CEED: http://github.com/ceed 7 8 #include <ceed.h> 9 #include <ceed/backend.h> 10 #include <stdbool.h> 11 #include <string.h> 12 #include <valgrind/memcheck.h> 13 14 #include "ceed-memcheck.h" 15 16 //------------------------------------------------------------------------------ 17 // QFunctionContext has valid data 18 //------------------------------------------------------------------------------ 19 static int CeedQFunctionContextHasValidData_Memcheck(CeedQFunctionContext ctx, bool *has_valid_data) { 20 CeedQFunctionContext_Memcheck *impl; 21 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, (void *)&impl)); 22 23 *has_valid_data = !!impl->data; 24 25 return CEED_ERROR_SUCCESS; 26 } 27 28 //------------------------------------------------------------------------------ 29 // QFunctionContext has borrowed data 30 //------------------------------------------------------------------------------ 31 static int CeedQFunctionContextHasBorrowedDataOfType_Memcheck(CeedQFunctionContext ctx, CeedMemType mem_type, bool *has_borrowed_data_of_type) { 32 CeedQFunctionContext_Memcheck *impl; 33 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, (void *)&impl)); 34 Ceed ceed; 35 CeedCallBackend(CeedQFunctionContextGetCeed(ctx, &ceed)); 36 37 switch (mem_type) { 38 case CEED_MEM_HOST: 39 *has_borrowed_data_of_type = !!impl->data_borrowed; 40 break; 41 default: 42 // LCOV_EXCL_START 43 return CeedError(ceed, CEED_ERROR_BACKEND, "Can only set HOST memory for this backend"); 44 // LCOV_EXCL_STOP 45 break; 46 } 47 48 return CEED_ERROR_SUCCESS; 49 } 50 51 //------------------------------------------------------------------------------ 52 // QFunctionContext Set Data 53 //------------------------------------------------------------------------------ 54 static int CeedQFunctionContextSetData_Memcheck(CeedQFunctionContext ctx, CeedMemType mem_type, CeedCopyMode copy_mode, void *data) { 55 CeedQFunctionContext_Memcheck *impl; 56 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, (void *)&impl)); 57 size_t ctx_size; 58 CeedCallBackend(CeedQFunctionContextGetContextSize(ctx, &ctx_size)); 59 Ceed ceed; 60 CeedCallBackend(CeedQFunctionContextGetCeed(ctx, &ceed)); 61 62 if (mem_type != CEED_MEM_HOST) { 63 // LCOV_EXCL_START 64 return CeedError(ceed, CEED_ERROR_BACKEND, "Can only set HOST memory for this backend"); 65 // LCOV_EXCL_STOP 66 } 67 68 CeedCallBackend(CeedFree(&impl->data_allocated)); 69 CeedCallBackend(CeedFree(&impl->data_owned)); 70 switch (copy_mode) { 71 case CEED_COPY_VALUES: 72 CeedCallBackend(CeedMallocArray(1, ctx_size, &impl->data_owned)); 73 impl->data_borrowed = NULL; 74 impl->data = impl->data_owned; 75 memcpy(impl->data, data, ctx_size); 76 break; 77 case CEED_OWN_POINTER: 78 impl->data_owned = data; 79 impl->data_borrowed = NULL; 80 impl->data = data; 81 break; 82 case CEED_USE_POINTER: 83 impl->data_borrowed = data; 84 impl->data = data; 85 } 86 // Copy data to check ctx_size bounds 87 CeedCallBackend(CeedMallocArray(1, ctx_size, &impl->data_allocated)); 88 memcpy(impl->data_allocated, impl->data, ctx_size); 89 impl->data = impl->data_allocated; 90 VALGRIND_DISCARD(impl->mem_block_id); 91 impl->mem_block_id = VALGRIND_CREATE_BLOCK(impl->data, ctx_size, "'QFunction backend context data copy'"); 92 93 return CEED_ERROR_SUCCESS; 94 } 95 96 //------------------------------------------------------------------------------ 97 // QFunctionContext Take Data 98 //------------------------------------------------------------------------------ 99 static int CeedQFunctionContextTakeData_Memcheck(CeedQFunctionContext ctx, CeedMemType mem_type, void *data) { 100 CeedQFunctionContext_Memcheck *impl; 101 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, (void *)&impl)); 102 Ceed ceed; 103 CeedCallBackend(CeedQFunctionContextGetCeed(ctx, &ceed)); 104 105 if (mem_type != CEED_MEM_HOST) { 106 // LCOV_EXCL_START 107 return CeedError(ceed, CEED_ERROR_BACKEND, "Can only provide HOST memory for this backend"); 108 // LCOV_EXCL_STOP 109 } 110 111 *(void **)data = impl->data_borrowed; 112 impl->data_borrowed = NULL; 113 impl->data = NULL; 114 VALGRIND_DISCARD(impl->mem_block_id); 115 CeedCallBackend(CeedFree(&impl->data_allocated)); 116 117 return CEED_ERROR_SUCCESS; 118 } 119 120 //------------------------------------------------------------------------------ 121 // QFunctionContext Get Data 122 //------------------------------------------------------------------------------ 123 static int CeedQFunctionContextGetData_Memcheck(CeedQFunctionContext ctx, CeedMemType mem_type, void *data) { 124 CeedQFunctionContext_Memcheck *impl; 125 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, (void *)&impl)); 126 Ceed ceed; 127 CeedCallBackend(CeedQFunctionContextGetCeed(ctx, &ceed)); 128 129 if (mem_type != CEED_MEM_HOST) { 130 // LCOV_EXCL_START 131 return CeedError(ceed, CEED_ERROR_BACKEND, "Can only provide HOST memory for this backend"); 132 // LCOV_EXCL_STOP 133 } 134 135 *(void **)data = impl->data; 136 137 return CEED_ERROR_SUCCESS; 138 } 139 140 //------------------------------------------------------------------------------ 141 // QFunctionContext Get Data Read-Only 142 //------------------------------------------------------------------------------ 143 static int CeedQFunctionContextGetDataRead_Memcheck(CeedQFunctionContext ctx, CeedMemType mem_type, void *data) { 144 CeedQFunctionContext_Memcheck *impl; 145 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, (void *)&impl)); 146 size_t ctx_size; 147 CeedCallBackend(CeedQFunctionContextGetContextSize(ctx, &ctx_size)); 148 Ceed ceed; 149 CeedCallBackend(CeedQFunctionContextGetCeed(ctx, &ceed)); 150 151 CeedCallBackend(CeedQFunctionContextGetData_Memcheck(ctx, mem_type, data)); 152 153 // Make copy to verify no write occurred 154 CeedCallBackend(CeedMallocArray(1, ctx_size, &impl->data_read_only_copy)); 155 memcpy(impl->data_read_only_copy, *(void **)data, ctx_size); 156 157 return CEED_ERROR_SUCCESS; 158 } 159 160 //------------------------------------------------------------------------------ 161 // QFunctionContext Restore Data 162 //------------------------------------------------------------------------------ 163 static int CeedQFunctionContextRestoreData_Memcheck(CeedQFunctionContext ctx) { 164 size_t ctx_size; 165 CeedCallBackend(CeedQFunctionContextGetContextSize(ctx, &ctx_size)); 166 CeedQFunctionContext_Memcheck *impl; 167 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, (void *)&impl)); 168 169 if (impl->data_borrowed) { 170 memcpy(impl->data_borrowed, impl->data, ctx_size); 171 } 172 if (impl->data_owned) { 173 memcpy(impl->data_owned, impl->data, ctx_size); 174 } 175 176 return CEED_ERROR_SUCCESS; 177 } 178 179 //------------------------------------------------------------------------------ 180 // QFunctionContext Restore Data Read-Only 181 //------------------------------------------------------------------------------ 182 static int CeedQFunctionContextRestoreDataRead_Memcheck(CeedQFunctionContext ctx) { 183 size_t ctx_size; 184 CeedCallBackend(CeedQFunctionContextGetContextSize(ctx, &ctx_size)); 185 CeedQFunctionContext_Memcheck *impl; 186 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, (void *)&impl)); 187 Ceed ceed; 188 CeedCallBackend(CeedQFunctionContextGetCeed(ctx, &ceed)); 189 190 if (memcmp(impl->data, impl->data_read_only_copy, ctx_size)) { 191 // LCOV_EXCL_START 192 return CeedError(ceed, CEED_ERROR_BACKEND, "Context data changed while accessed in read-only mode"); 193 // LCOV_EXCL_STOP 194 } 195 196 CeedCallBackend(CeedFree(&impl->data_read_only_copy)); 197 198 return CEED_ERROR_SUCCESS; 199 } 200 201 //------------------------------------------------------------------------------ 202 // QFunctionContext destroy user data 203 //------------------------------------------------------------------------------ 204 static int CeedQFunctionContextDataDestroy_Memcheck(CeedQFunctionContext ctx) { 205 CeedQFunctionContext_Memcheck *impl; 206 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl)); 207 CeedQFunctionContextDataDestroyUser data_destroy_function; 208 CeedMemType data_destroy_mem_type; 209 CeedCallBackend(CeedQFunctionContextGetDataDestroy(ctx, &data_destroy_mem_type, &data_destroy_function)); 210 Ceed ceed; 211 CeedCallBackend(CeedQFunctionContextGetCeed(ctx, &ceed)); 212 213 if (data_destroy_mem_type != CEED_MEM_HOST) { 214 // LCOV_EXCL_START 215 return CeedError(ceed, CEED_ERROR_BACKEND, "Can only destroy HOST memory for this backend"); 216 // LCOV_EXCL_STOP 217 } 218 219 if (data_destroy_function) { 220 CeedCallBackend(data_destroy_function(impl->data_borrowed ? impl->data_borrowed : impl->data_owned)); 221 } 222 CeedCallBackend(CeedFree(&impl->data_allocated)); 223 224 return CEED_ERROR_SUCCESS; 225 } 226 227 //------------------------------------------------------------------------------ 228 // QFunctionContext Destroy 229 //------------------------------------------------------------------------------ 230 static int CeedQFunctionContextDestroy_Memcheck(CeedQFunctionContext ctx) { 231 CeedQFunctionContext_Memcheck *impl; 232 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl)); 233 234 CeedCallBackend(CeedFree(&impl->data_allocated)); 235 CeedCallBackend(CeedFree(&impl->data_owned)); 236 CeedCallBackend(CeedFree(&impl)); 237 return CEED_ERROR_SUCCESS; 238 } 239 240 //------------------------------------------------------------------------------ 241 // QFunctionContext Create 242 //------------------------------------------------------------------------------ 243 int CeedQFunctionContextCreate_Memcheck(CeedQFunctionContext ctx) { 244 CeedQFunctionContext_Memcheck *impl; 245 Ceed ceed; 246 CeedCallBackend(CeedQFunctionContextGetCeed(ctx, &ceed)); 247 248 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "HasValidData", CeedQFunctionContextHasValidData_Memcheck)); 249 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "HasBorrowedDataOfType", CeedQFunctionContextHasBorrowedDataOfType_Memcheck)); 250 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "SetData", CeedQFunctionContextSetData_Memcheck)); 251 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "TakeData", CeedQFunctionContextTakeData_Memcheck)); 252 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "GetData", CeedQFunctionContextGetData_Memcheck)); 253 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "GetDataRead", CeedQFunctionContextGetDataRead_Memcheck)); 254 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "RestoreData", CeedQFunctionContextRestoreData_Memcheck)); 255 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "RestoreDataRead", CeedQFunctionContextRestoreDataRead_Memcheck)); 256 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "DataDestroy", CeedQFunctionContextDataDestroy_Memcheck)); 257 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "Destroy", CeedQFunctionContextDestroy_Memcheck)); 258 259 CeedCallBackend(CeedCalloc(1, &impl)); 260 CeedCallBackend(CeedQFunctionContextSetBackendData(ctx, impl)); 261 262 return CEED_ERROR_SUCCESS; 263 } 264 265 //------------------------------------------------------------------------------ 266