atrtp.c (6534B)
1 /* Copyright (C) 2022, 2023 |Méso|Star> (contact@meso-star.com) 2 * Copyright (C) 2020, 2021 Centre National de la Recherche Scientifique 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17 #define _POSIX_C_SOURCE 200809L /* mmap support */ 18 #define _DEFAULT_SOURCE 1 /* MAP_POPULATE support */ 19 #define _BSD_SOURCE 1 /* MAP_POPULATE for glibc < 2.19 */ 20 21 #include "atrtp.h" 22 #include "atrtp_c.h" 23 #include "atrtp_log.h" 24 25 #include <unistd.h> 26 27 #include <errno.h> 28 #include <sys/mman.h> /* mmap */ 29 30 /******************************************************************************* 31 * Helper functions 32 ******************************************************************************/ 33 static void 34 reset_atrtp(struct atrtp* atrtp) 35 { 36 ASSERT(atrtp); 37 atrtp->pagesize = 0; 38 atrtp->nnodes = 0; 39 if(atrtp->props) munmap(atrtp->props, atrtp->map_len); 40 atrtp->props = NULL; 41 atrtp->map_len = 0; 42 } 43 44 static res_T 45 load_stream(struct atrtp* atrtp, FILE* stream, const char* stream_name) 46 { 47 off_t offset; 48 size_t filesz; 49 res_T res = RES_OK; 50 ASSERT(atrtp && stream && stream_name); 51 52 reset_atrtp(atrtp); 53 54 /* Read file header */ 55 #define READ(Var, N, Name) { \ 56 if(fread((Var), sizeof(*(Var)), (N), stream) != (N)) { \ 57 log_err(atrtp, "%s: could not read the %s.\n", stream_name, (Name)); \ 58 res = RES_IO_ERR; \ 59 goto error; \ 60 } \ 61 } (void)0 62 READ(&atrtp->pagesize, 1, "page size"); 63 READ(&atrtp->nnodes, 1, "number of nodes"); 64 #undef READ 65 66 if(!IS_ALIGNED(atrtp->pagesize, atrtp->pagesize_os)) { 67 log_err(atrtp, 68 "%s: invalid page size %li. The page size attribute must be aligned on " 69 "the page size of the operating system (%lu).\n", 70 stream_name, atrtp->pagesize, (unsigned long)atrtp->pagesize_os); 71 res = RES_BAD_ARG; 72 goto error; 73 } 74 75 /* Compute the length in bytes of the data to map */ 76 atrtp->map_len = atrtp->nnodes * sizeof(double[ATRTP_COUNT__]); 77 atrtp->map_len = ALIGN_SIZE(atrtp->map_len, (size_t)atrtp->pagesize); 78 79 /* Find the offsets of the positions/indices data into the stream */ 80 offset = (off_t)ALIGN_SIZE((uint64_t)ftell(stream), atrtp->pagesize); 81 82 /* Retrieve the overall filesize */ 83 fseek(stream, 0, SEEK_END); 84 filesz = (size_t)ftell(stream); 85 86 /* Check that the file has sufficient data */ 87 if((size_t)offset + atrtp->map_len > filesz) { 88 log_err(atrtp, 89 "%s: the thermodynamic properties to load exceed the file size.\n", 90 stream_name); 91 res = RES_IO_ERR; 92 goto error; 93 } 94 95 /* Map the thermodynamic properties */ 96 atrtp->props = mmap(NULL, atrtp->map_len, PROT_READ, 97 MAP_PRIVATE|MAP_POPULATE, fileno(stream), offset); 98 if(atrtp->props == MAP_FAILED) { 99 log_err(atrtp, "%s: could not map the thermodynamic properties --%s.\n", 100 stream_name, strerror(errno)); 101 res = RES_IO_ERR; 102 goto error; 103 } 104 105 exit: 106 return res; 107 error: 108 reset_atrtp(atrtp); 109 goto exit; 110 } 111 112 static void 113 release_atrtp(ref_T* ref) 114 { 115 struct atrtp* atrtp; 116 ASSERT(ref); 117 atrtp = CONTAINER_OF(ref, struct atrtp, ref); 118 reset_atrtp(atrtp); 119 if(atrtp->logger == &atrtp->logger__) logger_release(&atrtp->logger__); 120 MEM_RM(atrtp->allocator, atrtp); 121 } 122 123 /******************************************************************************* 124 * Exported functions 125 ******************************************************************************/ 126 res_T 127 atrtp_create 128 (struct logger* logger, /* NULL <=> use default logger */ 129 struct mem_allocator* mem_allocator, /* NULL <=> use default allocator */ 130 const int verbose, /* Verbosity level */ 131 struct atrtp** out_atrtp) 132 { 133 struct atrtp* atrtp = NULL; 134 struct mem_allocator* allocator = NULL; 135 res_T res = RES_OK; 136 137 if(!out_atrtp) { 138 res = RES_BAD_ARG; 139 goto error; 140 } 141 142 allocator = mem_allocator ? mem_allocator : &mem_default_allocator; 143 atrtp = MEM_CALLOC(allocator, 1, sizeof(*atrtp)); 144 if(!atrtp) { 145 if(verbose) { 146 #define ERR_STR "Could not allocate the AtrTP device.\n" 147 if(logger) { 148 logger_print(logger, LOG_ERROR, ERR_STR); 149 } else { 150 fprintf(stderr, MSG_ERROR_PREFIX ERR_STR); 151 } 152 #undef ERR_STR 153 } 154 res = RES_MEM_ERR; 155 goto error; 156 } 157 ref_init(&atrtp->ref); 158 atrtp->allocator = allocator; 159 atrtp->verbose = verbose; 160 atrtp->pagesize_os = (size_t)sysconf(_SC_PAGESIZE); 161 if(logger) { 162 atrtp->logger = logger; 163 } else { 164 setup_log_default(atrtp); 165 } 166 167 exit: 168 if(out_atrtp) *out_atrtp = atrtp; 169 return res; 170 error: 171 if(atrtp) { 172 ATRTP(ref_put(atrtp)); 173 atrtp = NULL; 174 } 175 goto exit; 176 } 177 178 res_T 179 atrtp_ref_get(struct atrtp* atrtp) 180 { 181 if(!atrtp) return RES_BAD_ARG; 182 ref_get(&atrtp->ref); 183 return RES_OK; 184 } 185 186 res_T 187 atrtp_ref_put(struct atrtp* atrtp) 188 { 189 if(!atrtp) return RES_BAD_ARG; 190 ref_put(&atrtp->ref, release_atrtp); 191 return RES_OK; 192 } 193 194 res_T 195 atrtp_load(struct atrtp* atrtp, const char* path) 196 { 197 FILE* file = NULL; 198 res_T res = RES_OK; 199 200 if(!atrtp || !path) { 201 res = RES_BAD_ARG; 202 goto error; 203 } 204 205 file = fopen(path, "r"); 206 if(!file) { 207 log_err(atrtp, "%s: error opening file `%s'.\n", FUNC_NAME, path); 208 res = RES_IO_ERR; 209 goto error; 210 } 211 212 res = load_stream(atrtp, file, path); 213 if(res != RES_OK) goto error; 214 215 exit: 216 if(file) fclose(file); 217 return res; 218 error: 219 goto exit; 220 } 221 222 res_T 223 atrtp_load_stream 224 (struct atrtp* atrtp, 225 FILE* stream, 226 const char* stream_name) 227 { 228 if(!atrtp || !stream) return RES_BAD_ARG; 229 return load_stream(atrtp, stream, stream_name ? stream_name : "<stream>"); 230 } 231 232 res_T 233 atrtp_get_desc(const struct atrtp* atrtp, struct atrtp_desc* desc) 234 { 235 if(!atrtp || !desc) return RES_BAD_ARG; 236 desc->properties = atrtp->props; 237 desc->nnodes = (size_t)atrtp->nnodes; 238 return RES_OK; 239 } 240