2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
54 #include "thread_mpi/threads.h"
56 #include "gromacs/fileio/filenm.h"
57 #include "gromacs/fileio/md5.h"
58 #include "gromacs/utility/fatalerror.h"
59 #include "gromacs/utility/futil.h"
60 #include "gromacs/utility/smalloc.h"
62 #include "gmxfio-impl.h"
64 /* This is the new improved and thread safe version of gmxfio. */
68 /* the list of open files is a linked list, with a dummy element at its head;
69 it is initialized when the first file is opened. */
70 static t_fileio *open_files = NULL;
73 /* this mutex locks the open_files structure so that no two threads can
76 For now, we use this as a coarse grained lock on all file
77 insertion/deletion operations because it makes avoiding deadlocks
78 easier, and adds almost no overhead: the only overhead is during
79 opening and closing of files, or during global operations like
80 iterating along all open files. All these cases should be rare
81 during the simulation. */
82 static tMPI_Thread_mutex_t open_file_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
84 const char *eioNames[eioNR] =
86 "REAL", "INT", "GMX_STE_T", "UCHAR", "NUCHAR", "USHORT", "RVEC", "NRVEC",
90 /******************************************************************
94 ******************************************************************/
96 static int gmx_fio_int_flush(t_fileio* fio)
102 rc = fflush(fio->fp);
106 rc = fflush((FILE *) fio->xdr->x_private);
113 /* check the number of items given against the type */
114 void gmx_fio_check_nitem(int eio, int nitem, const char *file, int line)
116 if ((nitem != 1) && !((eio == eioNRVEC) || (eio == eioNUCHAR)))
119 "nitem (%d) may differ from 1 only for %s or %s, not for %s"
120 "(%s, %d)", nitem, eioNames[eioNUCHAR], eioNames[eioNRVEC],
121 eioNames[eio], file, line);
126 /* output a data type error. */
127 void gmx_fio_fe(t_fileio *fio, int eio, const char *desc,
128 const char *srcfile, int line)
131 gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d",
132 fio->bRead ? "read" : "write", desc, eio,
133 ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown",
137 /* lock the mutex associated with this fio. This needs to be done for every
138 type of access to the fio's elements. */
139 void gmx_fio_lock(t_fileio *fio)
141 tMPI_Lock_lock(&(fio->mtx));
143 /* unlock the mutex associated with this fio. */
144 void gmx_fio_unlock(t_fileio *fio)
146 tMPI_Lock_unlock(&(fio->mtx));
149 /* make a dummy head element, assuming we locked everything. */
150 static void gmx_fio_make_dummy(void)
155 open_files->fp = NULL;
156 open_files->fn = NULL;
157 open_files->next = open_files;
158 open_files->prev = open_files;
159 tMPI_Lock_init(&(open_files->mtx));
169 /***********************************************************************
171 * FILE LIST OPERATIONS
173 ***********************************************************************/
176 /* insert a new t_fileio into the list */
177 static void gmx_fio_insert(t_fileio *fio)
180 /* first lock the big open_files mutex. */
181 tMPI_Thread_mutex_lock(&open_file_mutex);
182 /* now check whether the dummy element has been allocated,
183 and allocate it if it hasn't */
184 gmx_fio_make_dummy();
186 /* and lock the fio we got and the list's head **/
188 gmx_fio_lock(open_files);
189 prev = open_files->prev;
190 /* lock the element after the current one */
191 if (prev != open_files)
196 /* now do the actual insertion: */
197 fio->next = open_files;
198 open_files->prev = fio;
202 /* now unlock all our locks */
203 if (prev != open_files)
205 gmx_fio_unlock(prev);
207 gmx_fio_unlock(open_files);
210 /* now unlock the big open_files mutex. */
211 tMPI_Thread_mutex_unlock(&open_file_mutex);
214 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
216 NOTE: We also assume that the open_file_mutex has been locked */
217 static void gmx_fio_remove(t_fileio *fio)
221 /* lock prev, because we're changing it */
222 gmx_fio_lock(fio->prev);
224 /* now set the prev's pointer */
225 fio->prev->next = fio->next;
226 gmx_fio_unlock(fio->prev);
228 /* with the next ptr, we can simply lock while the original was locked */
229 gmx_fio_lock(fio->next);
230 fio->next->prev = fio->prev;
231 gmx_fio_unlock(fio->next);
233 /* and make sure we point nowhere in particular */
234 fio->next = fio->prev = fio;
238 /* get the first open file, or NULL if there is none.
239 Returns a locked fio. */
240 static t_fileio *gmx_fio_get_first(void)
243 /* first lock the big open_files mutex and the dummy's mutex */
245 /* first lock the big open_files mutex. */
246 tMPI_Thread_mutex_lock(&open_file_mutex);
247 gmx_fio_make_dummy();
249 gmx_fio_lock(open_files);
250 ret = open_files->next;
253 /* check whether there were any to begin with */
254 if (ret == open_files)
256 /* after this, the open_file pointer should never change */
261 gmx_fio_lock(open_files->next);
263 gmx_fio_unlock(open_files);
269 /* get the next open file, or NULL if there is none.
270 Unlocks the previous fio and locks the next one. */
271 static t_fileio *gmx_fio_get_next(t_fileio *fio)
276 /* check if that was the last one */
277 if (fio->next == open_files)
280 tMPI_Thread_mutex_unlock(&open_file_mutex);
291 /* Stop looping through the open_files. Unlocks the global lock. */
292 static void gmx_fio_stop_getting_next(t_fileio *fio)
295 tMPI_Thread_mutex_unlock(&open_file_mutex);
301 /*****************************************************************
305 *****************************************************************/
306 t_fileio *gmx_fio_open(const char *fn, const char *mode)
308 t_fileio *fio = NULL;
311 gmx_bool bRead, bReadWrite;
314 /* sanitize the mode string */
315 if (strncmp(mode, "r+", 2) == 0)
317 strcpy(newmode, "r+");
319 else if (mode[0] == 'r')
321 strcpy(newmode, "r");
323 else if (strncmp(mode, "w+", 2) == 0)
325 strcpy(newmode, "w+");
327 else if (mode[0] == 'w')
329 strcpy(newmode, "w");
331 else if (strncmp(mode, "a+", 2) == 0)
333 strcpy(newmode, "a+");
335 else if (mode[0] == 'a')
337 strcpy(newmode, "a");
341 gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'", mode);
344 /* Check if it should be opened as a binary file */
345 if (!ftp_is_text(fn2ftp(fn)))
347 /* Not ascii, add b to file mode */
348 if ((strchr(newmode, 'b') == NULL) && (strchr(newmode, 'B') == NULL))
350 strcat(newmode, "b");
355 tMPI_Lock_init(&(fio->mtx));
356 bRead = (newmode[0] == 'r' && newmode[1] != '+');
357 bReadWrite = (newmode[1] == '+');
362 if (fn2ftp(fn) == efTNG)
364 gmx_incons("gmx_fio_open may not be used to open TNG files");
366 fio->iFTP = fn2ftp(fn);
367 fio->fn = gmx_strdup(fn);
369 /* If this file type is in the list of XDR files, open it like that */
370 if (ftp_is_xdr(fio->iFTP))
372 /* First check whether we have to make a backup,
373 * only for writing, not for read or append.
375 if (newmode[0] == 'w')
378 /* only make backups for normal gromacs */
384 /* Check whether file exists */
391 fio->fp = gmx_ffopen(fn, newmode);
393 /* determine the XDR direction */
394 if (newmode[0] == 'w' || newmode[0] == 'a')
396 fio->xdrmode = XDR_ENCODE;
400 fio->xdrmode = XDR_DECODE;
404 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
408 /* If it is not, open it as a regular file */
409 fio->fp = gmx_ffopen(fn, newmode);
412 /* for appending seek to end of file to make sure ftell gives correct position
413 * important for checkpointing */
414 if (newmode[0] == 'a')
416 gmx_fseek(fio->fp, 0, SEEK_END);
420 fio->bReadWrite = bReadWrite;
421 fio->bDouble = (sizeof(real) == sizeof(double));
425 /* and now insert this file into the list of open files. */
430 static int gmx_fio_close_locked(t_fileio *fio)
436 gmx_fatal(FARGS, "File %s closed twice!\n", fio->fn);
439 if (ftp_is_xdr(fio->iFTP))
441 xdr_destroy(fio->xdr);
447 rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
455 int gmx_fio_close(t_fileio *fio)
459 /* first lock the big open_files mutex. */
460 /* We don't want two processes operating on the list at the same time */
461 tMPI_Thread_mutex_lock(&open_file_mutex);
463 if (fio->iFTP == efTNG)
465 gmx_incons("gmx_fio_close should not be called on a TNG file");
468 /* first remove it from the list */
470 rc = gmx_fio_close_locked(fio);
476 tMPI_Thread_mutex_unlock(&open_file_mutex);
481 /* close only fp but keep FIO entry. */
482 int gmx_fio_fp_close(t_fileio *fio)
486 if (!ftp_is_xdr(fio->iFTP))
488 rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
496 FILE * gmx_fio_fopen(const char *fn, const char *mode)
501 fio = gmx_fio_open(fn, mode);
509 int gmx_fio_fclose(FILE *fp)
512 t_fileio *found = NULL;
515 cur = gmx_fio_get_first();
520 rc = gmx_fio_close_locked(cur);
522 gmx_fio_stop_getting_next(cur);
527 cur = gmx_fio_get_next(cur);
533 /* internal variant of get_file_md5 that operates on a locked file */
534 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
535 unsigned char digest[])
537 /*1MB: large size important to catch almost identical files */
538 #define CPT_CHK_LEN 1048576
542 gmx_off_t seek_offset;
545 seek_offset = offset - CPT_CHK_LEN;
550 read_len = offset - seek_offset;
553 if (fio->fp && fio->bReadWrite)
555 ret = gmx_fseek(fio->fp, seek_offset, SEEK_SET);
558 gmx_fseek(fio->fp, 0, SEEK_END);
561 if (ret) /*either no fp, not readwrite, or fseek not successful */
566 snew(buf, CPT_CHK_LEN);
567 /* the read puts the file position back to offset */
568 if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
570 /* not fatal: md5sum check to prevent overwriting files
571 * works (less safe) without
575 fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
578 else if (feof(fio->fp))
581 * For long runs that checkpoint frequently but write e.g. logs
582 * infrequently we don't want to issue lots of warnings before we
583 * have written anything to the log.
587 fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
594 "\nTrying to get md5sum: Unknown reason for short read: %s\n",
598 gmx_fseek(fio->fp, 0, SEEK_END);
602 gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows
603 it gives problems otherwise*/
607 fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
612 gmx_md5_init(&state);
613 gmx_md5_append(&state, buf, read_len);
614 gmx_md5_finish(&state, digest);
623 * fio: file to compute md5 for
624 * offset: starting pointer of region to use for md5
625 * digest: return array of md5 sum
627 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
628 unsigned char digest[])
633 ret = gmx_fio_int_get_file_md5(fio, offset, digest);
639 /* The fio_mutex should ALWAYS be locked when this function is called */
640 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
644 /* Flush the file, so we are sure it is written */
645 if (gmx_fio_int_flush(fio))
650 "Cannot write file '%s'; maybe you are out of disk space?",
655 /* We cannot count on XDR being able to write 64-bit integers,
656 so separate into high/low 32-bit values.
657 In case the filesystem has 128-bit offsets we only care
658 about the first 64 bits - we'll have to fix
659 this when exabyte-size output files are common...
661 *offset = gmx_ftell(fio->fp);
666 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
669 int i, nfiles, rc, nalloc;
672 gmx_file_position_t * outputfiles;
678 /* pre-allocate 100 files */
680 snew(outputfiles, nalloc);
682 cur = gmx_fio_get_first();
685 /* Skip the checkpoint files themselves, since they could be open when
686 we call this routine... */
687 if (cur->bOpen && !cur->bRead && cur->iFTP != efCPT)
690 /* This is an output file currently open for writing, add it */
691 if (nfiles == nalloc)
694 srenew(outputfiles, nalloc);
697 strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
699 /* Get the file position */
700 gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
702 outputfiles[nfiles].chksum_size
703 = gmx_fio_int_get_file_md5(cur,
704 outputfiles[nfiles].offset,
705 outputfiles[nfiles].chksum);
710 cur = gmx_fio_get_next(cur);
713 *p_outputfiles = outputfiles;
719 void gmx_fio_checktype(t_fileio *fio)
721 if (!ftp_is_xdr(fio->iFTP))
723 gmx_fatal(FARGS, "Can not read/write topologies to file type %s",
730 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
733 fio->bDouble = bDouble;
737 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
740 fio->bDebug = bDebug;
744 char *gmx_fio_getname(t_fileio *fio)
754 int gmx_fio_getftp(t_fileio* fio)
765 void gmx_fio_rewind(t_fileio* fio)
771 xdr_destroy(fio->xdr);
773 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
783 int gmx_fio_flush(t_fileio* fio)
788 ret = gmx_fio_int_flush(fio);
796 static int gmx_fio_int_fsync(t_fileio *fio)
804 rc = gmx_fsync(fio->fp);
806 else if (fio->xdr) /* this should normally not happen */
808 rc = gmx_fsync((FILE*) fio->xdr->x_private);
809 /* ^ is this actually OK? */
816 int gmx_fio_fsync(t_fileio *fio)
821 rc = gmx_fio_int_fsync(fio);
829 t_fileio *gmx_fio_all_output_fsync(void)
831 t_fileio *ret = NULL;
834 cur = gmx_fio_get_first();
837 if (cur->bOpen && !cur->bRead)
839 /* if any of them fails, return failure code */
840 int rc = gmx_fio_int_fsync(cur);
846 cur = gmx_fio_get_next(cur);
849 /* in addition, we force these to be written out too, if they're being
850 redirected. We don't check for errors because errors most likely mean
851 that they're not redirected. */
854 #if (defined(HAVE_FSYNC))
855 /* again, fahcore defines HAVE_FSYNC and fsync() */
856 fsync(STDOUT_FILENO);
857 fsync(STDERR_FILENO);
864 gmx_off_t gmx_fio_ftell(t_fileio* fio)
871 ret = gmx_ftell(fio->fp);
877 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
884 rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
895 FILE *gmx_fio_getfp(t_fileio *fio)
908 XDR *gmx_fio_getxdr(t_fileio* fio)
922 gmx_bool gmx_fio_getread(t_fileio* fio)
933 int xtc_seek_time(t_fileio *fio, real time, int natoms, gmx_bool bSeekForwardOnly)
938 ret = xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms, bSeekForwardOnly);