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, 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/gmxfio_int.h"
58 #include "gromacs/fileio/md5.h"
59 #include "gromacs/legacyheaders/macros.h"
60 #include "gromacs/utility/cstringutil.h"
61 #include "gromacs/utility/fatalerror.h"
62 #include "gromacs/utility/futil.h"
63 #include "gromacs/utility/smalloc.h"
65 /* This is the new improved and thread safe version of gmxfio. */
69 /* the list of open files is a linked list, with a dummy element at its head;
70 it is initialized when the first file is opened. */
71 static t_fileio *open_files = NULL;
74 /* this mutex locks the open_files structure so that no two threads can
77 For now, we use this as a coarse grained lock on all file
78 insertion/deletion operations because it makes avoiding deadlocks
79 easier, and adds almost no overhead: the only overhead is during
80 opening and closing of files, or during global operations like
81 iterating along all open files. All these cases should be rare
82 during the simulation. */
83 static tMPI_Thread_mutex_t open_file_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
86 /* These simple lists define the I/O type for these files */
87 static const int ftpXDR[] =
88 { efTPR, efTRR, efEDR, efXTC, efTNG, efMTX, efCPT };
89 static const int ftpASC[] =
90 { efGRO, efPDB, efG96 };
91 static const int ftpBIN[] =
94 static const int ftpXML[] =
98 const char *eioNames[eioNR] =
100 "REAL", "INT", "GMX_STE_T", "UCHAR", "NUCHAR", "USHORT", "RVEC", "NRVEC",
104 /******************************************************************
106 * Internal functions:
108 ******************************************************************/
110 static int gmx_fio_int_flush(t_fileio* fio)
116 rc = fflush(fio->fp);
120 rc = fflush((FILE *) fio->xdr->x_private);
126 /* returns TRUE if the file type ftp is in the set set */
127 static gmx_bool in_ftpset(int ftp, int nset, const int set[])
133 for (i = 0; (i < nset); i++)
146 extern void gmx_fio_set_comment(t_fileio *fio, const char *comment)
148 fio->comment = comment;
151 extern void gmx_fio_unset_comment(t_fileio *fio)
157 const char *gmx_fio_dbgstr(t_fileio *fio, const char *desc, char *buf)
161 /* set to empty string */
166 snprintf(buf, GMX_FIO_BUFLEN, " ; %s %s", fio->comment ? fio->comment : "", desc);
172 /* check the number of items given against the type */
173 void gmx_fio_check_nitem(int eio, int nitem, const char *file, int line)
175 if ((nitem != 1) && !((eio == eioNRVEC) || (eio == eioNUCHAR)))
178 "nitem (%d) may differ from 1 only for %s or %s, not for %s"
179 "(%s, %d)", nitem, eioNames[eioNUCHAR], eioNames[eioNRVEC],
180 eioNames[eio], file, line);
185 /* output a data type error. */
186 void gmx_fio_fe(t_fileio *fio, int eio, const char *desc,
187 const char *srcfile, int line)
190 gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d",
191 fio->bRead ? "read" : "write", desc, eio,
192 ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown",
197 /* set the reader/writer functions based on the file type */
198 static void gmx_fio_set_iotype(t_fileio *fio)
200 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
203 fio->iotp = &xdr_iotype;
205 gmx_fatal(FARGS, "Sorry, no XDR");
208 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
210 fio->iotp = &asc_iotype;
212 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
214 fio->iotp = &bin_iotype;
217 else if (in_ftpset(fio->iFTP, asize(ftpXML), ftpXML))
219 fio->iotp = &dummy_iotype;
224 fio->iotp = &dummy_iotype;
229 /* lock the mutex associated with this fio. This needs to be done for every
230 type of access to the fio's elements. */
231 void gmx_fio_lock(t_fileio *fio)
233 tMPI_Lock_lock(&(fio->mtx));
235 /* unlock the mutex associated with this fio. */
236 void gmx_fio_unlock(t_fileio *fio)
238 tMPI_Lock_unlock(&(fio->mtx));
241 /* make a dummy head element, assuming we locked everything. */
242 static void gmx_fio_make_dummy(void)
247 open_files->fp = NULL;
248 open_files->fn = NULL;
249 open_files->next = open_files;
250 open_files->prev = open_files;
251 tMPI_Lock_init(&(open_files->mtx));
261 /***********************************************************************
263 * FILE LIST OPERATIONS
265 ***********************************************************************/
268 /* insert a new t_fileio into the list */
269 static void gmx_fio_insert(t_fileio *fio)
272 /* first lock the big open_files mutex. */
273 tMPI_Thread_mutex_lock(&open_file_mutex);
274 /* now check whether the dummy element has been allocated,
275 and allocate it if it hasn't */
276 gmx_fio_make_dummy();
278 /* and lock the fio we got and the list's head **/
280 gmx_fio_lock(open_files);
281 prev = open_files->prev;
282 /* lock the element after the current one */
283 if (prev != open_files)
288 /* now do the actual insertion: */
289 fio->next = open_files;
290 open_files->prev = fio;
294 /* now unlock all our locks */
295 if (prev != open_files)
297 gmx_fio_unlock(prev);
299 gmx_fio_unlock(open_files);
302 /* now unlock the big open_files mutex. */
303 tMPI_Thread_mutex_unlock(&open_file_mutex);
306 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
308 NOTE: We also assume that the open_file_mutex has been locked */
309 static void gmx_fio_remove(t_fileio *fio)
313 /* lock prev, because we're changing it */
314 gmx_fio_lock(fio->prev);
316 /* now set the prev's pointer */
317 fio->prev->next = fio->next;
318 gmx_fio_unlock(fio->prev);
320 /* with the next ptr, we can simply lock while the original was locked */
321 gmx_fio_lock(fio->next);
322 fio->next->prev = fio->prev;
323 gmx_fio_unlock(fio->next);
325 /* and make sure we point nowhere in particular */
326 fio->next = fio->prev = fio;
330 /* get the first open file, or NULL if there is none.
331 Returns a locked fio. */
332 static t_fileio *gmx_fio_get_first(void)
335 /* first lock the big open_files mutex and the dummy's mutex */
337 /* first lock the big open_files mutex. */
338 tMPI_Thread_mutex_lock(&open_file_mutex);
339 gmx_fio_make_dummy();
341 gmx_fio_lock(open_files);
342 ret = open_files->next;
345 /* check whether there were any to begin with */
346 if (ret == open_files)
348 /* after this, the open_file pointer should never change */
353 gmx_fio_lock(open_files->next);
355 gmx_fio_unlock(open_files);
361 /* get the next open file, or NULL if there is none.
362 Unlocks the previous fio and locks the next one. */
363 static t_fileio *gmx_fio_get_next(t_fileio *fio)
368 /* check if that was the last one */
369 if (fio->next == open_files)
372 tMPI_Thread_mutex_unlock(&open_file_mutex);
383 /* Stop looping through the open_files. Unlocks the global lock. */
384 static void gmx_fio_stop_getting_next(t_fileio *fio)
387 tMPI_Thread_mutex_unlock(&open_file_mutex);
393 /*****************************************************************
397 *****************************************************************/
398 t_fileio *gmx_fio_open(const char *fn, const char *mode)
400 t_fileio *fio = NULL;
403 gmx_bool bRead, bReadWrite;
406 /* sanitize the mode string */
407 if (strncmp(mode, "r+", 2) == 0)
409 strcpy(newmode, "r+");
411 else if (mode[0] == 'r')
413 strcpy(newmode, "r");
415 else if (strncmp(mode, "w+", 2) == 0)
417 strcpy(newmode, "w+");
419 else if (mode[0] == 'w')
421 strcpy(newmode, "w");
423 else if (strncmp(mode, "a+", 2) == 0)
425 strcpy(newmode, "a+");
427 else if (mode[0] == 'a')
429 strcpy(newmode, "a");
433 gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'", mode);
436 /* Check if it should be opened as a binary file */
437 if (strncmp(ftp2ftype(fn2ftp(fn)), "ASCII", 5))
439 /* Not ascii, add b to file mode */
440 if ((strchr(newmode, 'b') == NULL) && (strchr(newmode, 'B') == NULL))
442 strcat(newmode, "b");
447 tMPI_Lock_init(&(fio->mtx));
448 bRead = (newmode[0] == 'r' && newmode[1] != '+');
449 bReadWrite = (newmode[1] == '+');
454 fio->iFTP = fn2ftp(fn);
455 fio->fn = gmx_strdup(fn);
458 /* If this file type is in the list of XDR files, open it like that */
459 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
461 /* First check whether we have to make a backup,
462 * only for writing, not for read or append.
464 if (newmode[0] == 'w')
467 /* only make backups for normal gromacs */
473 /* Check whether file exists */
479 if (fn2ftp(fn) == efTNG)
481 gmx_incons("gmx_fio_open may not be used to open TNG files");
484 fio->fp = gmx_ffopen(fn, newmode);
486 /* determine the XDR direction */
487 if (newmode[0] == 'w' || newmode[0] == 'a')
489 fio->xdrmode = XDR_ENCODE;
493 fio->xdrmode = XDR_DECODE;
497 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
501 /* If it is not, open it as a regular file */
502 fio->fp = gmx_ffopen(fn, newmode);
505 /* for appending seek to end of file to make sure ftell gives correct position
506 * important for checkpointing */
507 if (newmode[0] == 'a')
509 gmx_fseek(fio->fp, 0, SEEK_END);
513 fio->bReadWrite = bReadWrite;
514 fio->bDouble = (sizeof(real) == sizeof(double));
518 /* set the reader/writer functions */
519 gmx_fio_set_iotype(fio);
521 /* and now insert this file into the list of open files. */
526 static int gmx_fio_close_locked(t_fileio *fio)
532 gmx_fatal(FARGS, "File %s closed twice!\n", fio->fn);
535 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
537 xdr_destroy(fio->xdr);
541 /* Don't close stdin and stdout! */
542 if (!fio->bStdio && fio->fp != NULL)
544 rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
552 int gmx_fio_close(t_fileio *fio)
556 /* first lock the big open_files mutex. */
557 /* We don't want two processes operating on the list at the same time */
558 tMPI_Thread_mutex_lock(&open_file_mutex);
560 if (fio->iFTP == efTNG)
562 gmx_incons("gmx_fio_close should not be called on a TNG file");
565 /* first remove it from the list */
567 rc = gmx_fio_close_locked(fio);
573 tMPI_Thread_mutex_unlock(&open_file_mutex);
578 /* close only fp but keep FIO entry. */
579 int gmx_fio_fp_close(t_fileio *fio)
583 if (!in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR) && !fio->bStdio)
585 rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
593 FILE * gmx_fio_fopen(const char *fn, const char *mode)
598 fio = gmx_fio_open(fn, mode);
606 int gmx_fio_fclose(FILE *fp)
609 t_fileio *found = NULL;
612 cur = gmx_fio_get_first();
617 rc = gmx_fio_close_locked(cur);
619 gmx_fio_stop_getting_next(cur);
624 cur = gmx_fio_get_next(cur);
630 /* internal variant of get_file_md5 that operates on a locked file */
631 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
632 unsigned char digest[])
634 /*1MB: large size important to catch almost identical files */
635 #define CPT_CHK_LEN 1048576
639 gmx_off_t seek_offset;
642 seek_offset = offset - CPT_CHK_LEN;
647 read_len = offset - seek_offset;
650 if (fio->fp && fio->bReadWrite)
652 ret = gmx_fseek(fio->fp, seek_offset, SEEK_SET);
655 gmx_fseek(fio->fp, 0, SEEK_END);
658 if (ret) /*either no fp, not readwrite, or fseek not successful */
663 snew(buf, CPT_CHK_LEN);
664 /* the read puts the file position back to offset */
665 if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
667 /* not fatal: md5sum check to prevent overwriting files
668 * works (less safe) without
672 fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
675 else if (feof(fio->fp))
678 * For long runs that checkpoint frequently but write e.g. logs
679 * infrequently we don't want to issue lots of warnings before we
680 * have written anything to the log.
684 fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
691 "\nTrying to get md5sum: Unknown reason for short read: %s\n",
695 gmx_fseek(fio->fp, 0, SEEK_END);
699 gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows
700 it gives problems otherwise*/
704 fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
709 gmx_md5_init(&state);
710 gmx_md5_append(&state, buf, read_len);
711 gmx_md5_finish(&state, digest);
720 * fio: file to compute md5 for
721 * offset: starting pointer of region to use for md5
722 * digest: return array of md5 sum
724 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
725 unsigned char digest[])
730 ret = gmx_fio_int_get_file_md5(fio, offset, digest);
736 /* The fio_mutex should ALWAYS be locked when this function is called */
737 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
741 /* Flush the file, so we are sure it is written */
742 if (gmx_fio_int_flush(fio))
747 "Cannot write file '%s'; maybe you are out of disk space?",
752 /* We cannot count on XDR being able to write 64-bit integers,
753 so separate into high/low 32-bit values.
754 In case the filesystem has 128-bit offsets we only care
755 about the first 64 bits - we'll have to fix
756 this when exabyte-size output files are common...
758 *offset = gmx_ftell(fio->fp);
763 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
766 int i, nfiles, rc, nalloc;
769 gmx_file_position_t * outputfiles;
775 /* pre-allocate 100 files */
777 snew(outputfiles, nalloc);
779 cur = gmx_fio_get_first();
782 /* Skip the checkpoint files themselves, since they could be open when
783 we call this routine... */
784 /* also skip debug files (shoud be the only iFTP==efNR) */
788 cur->iFTP != efCPT &&
792 /* This is an output file currently open for writing, add it */
793 if (nfiles == nalloc)
796 srenew(outputfiles, nalloc);
799 strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
801 /* Get the file position */
802 gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
804 outputfiles[nfiles].chksum_size
805 = gmx_fio_int_get_file_md5(cur,
806 outputfiles[nfiles].offset,
807 outputfiles[nfiles].chksum);
812 cur = gmx_fio_get_next(cur);
815 *p_outputfiles = outputfiles;
821 void gmx_fio_checktype(t_fileio *fio)
823 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
827 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
831 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
836 else if (in_ftpset(fio->iFTP, asize(ftpXML), ftpXML))
843 gmx_fatal(FARGS, "Can not read/write topologies to file type %s",
850 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
853 fio->bDouble = bDouble;
857 gmx_bool gmx_fio_getdebug(t_fileio *fio)
868 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
871 fio->bDebug = bDebug;
875 char *gmx_fio_getname(t_fileio *fio)
885 int gmx_fio_getftp(t_fileio* fio)
896 void gmx_fio_rewind(t_fileio* fio)
902 xdr_destroy(fio->xdr);
904 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
914 int gmx_fio_flush(t_fileio* fio)
919 ret = gmx_fio_int_flush(fio);
927 static int gmx_fio_int_fsync(t_fileio *fio)
935 rc = gmx_fsync(fio->fp);
937 else if (fio->xdr) /* this should normally not happen */
939 rc = gmx_fsync((FILE*) fio->xdr->x_private);
940 /* ^ is this actually OK? */
947 int gmx_fio_fsync(t_fileio *fio)
952 rc = gmx_fio_int_fsync(fio);
960 t_fileio *gmx_fio_all_output_fsync(void)
962 t_fileio *ret = NULL;
965 cur = gmx_fio_get_first();
968 /* skip debug files (shoud be the only iFTP==efNR) */
974 /* if any of them fails, return failure code */
975 int rc = gmx_fio_int_fsync(cur);
981 cur = gmx_fio_get_next(cur);
984 /* in addition, we force these to be written out too, if they're being
985 redirected. We don't check for errors because errors most likely mean
986 that they're not redirected. */
989 #if (defined(HAVE_FSYNC))
990 /* again, fahcore defines HAVE_FSYNC and fsync() */
991 fsync(STDOUT_FILENO);
992 fsync(STDERR_FILENO);
999 gmx_off_t gmx_fio_ftell(t_fileio* fio)
1006 ret = gmx_ftell(fio->fp);
1008 gmx_fio_unlock(fio);
1012 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
1019 rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
1026 gmx_fio_unlock(fio);
1030 FILE *gmx_fio_getfp(t_fileio *fio)
1039 gmx_fio_unlock(fio);
1043 XDR *gmx_fio_getxdr(t_fileio* fio)
1052 gmx_fio_unlock(fio);
1057 gmx_bool gmx_fio_getread(t_fileio* fio)
1063 gmx_fio_unlock(fio);
1068 int xtc_seek_frame(t_fileio *fio, int frame, int natoms)
1073 ret = xdr_xtc_seek_frame(frame, fio->fp, fio->xdr, natoms);
1074 gmx_fio_unlock(fio);
1079 int xtc_seek_time(t_fileio *fio, real time, int natoms, gmx_bool bSeekForwardOnly)
1084 ret = xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms, bSeekForwardOnly);
1085 gmx_fio_unlock(fio);