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 * check out http://www.gromacs.org for more information.
7 * Copyright (c) 2012,2013, by the GROMACS development team, led by
8 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9 * others, as listed in the AUTHORS file in the top-level source
10 * directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
49 #include "gmx_fatal.h"
59 #include "thread_mpi.h"
62 #include "gmxfio_int.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;
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;
87 /* These simple lists define the I/O type for these files */
88 static const int ftpXDR[] =
89 { efTPR, efTRR, efEDR, efXTC, efMTX, efCPT };
90 static const int ftpASC[] =
91 { efTPA, efGRO, efPDB };
92 static const int ftpBIN[] =
95 const char *itemstr[eitemNR] =
97 "[header]", "[inputrec]", "[box]", "[topology]", "[coordinates]",
98 "[velocities]", "[forces]"
101 const char *eioNames[eioNR] =
103 "REAL", "INT", "GMX_STE_T", "UCHAR", "NUCHAR", "USHORT", "RVEC", "NRVEC",
109 /* Comment strings for TPA only */
110 const char *comment_str[eitemNR] = {
111 "; The header holds information on the number of atoms etc. and on whether\n"
112 "; certain items are present in the file or not.\n"
115 "; DO NOT EDIT THIS FILE BY HAND\n"
116 "; The GROMACS preprocessor performs a lot of checks on your input that\n"
117 "; you ignore when editing this. Your simulation may crash because of this\n",
118 "; The inputrec holds the parameters for MD such as the number of steps,\n"
119 "; the timestep and the cut-offs.\n",
120 "; The simulation box in nm.\n",
121 "; The topology section describes the topology of the molecules\n"
122 "; i.e. bonds, angles and dihedrals etc. and also holds the force field\n"
124 "; The atomic coordinates in nm\n",
125 "; The atomic velocities in nm/ps\n",
126 "; The forces on the atoms in nm/ps^2\n"
132 /******************************************************************
134 * Internal functions:
136 ******************************************************************/
138 static int gmx_fio_int_flush(t_fileio* fio)
144 rc = fflush(fio->fp);
148 rc = fflush((FILE *) fio->xdr->x_private);
154 /* returns TRUE if the file type ftp is in the set set */
155 static gmx_bool in_ftpset(int ftp, int nset, const int set[])
161 for (i = 0; (i < nset); i++)
174 extern void gmx_fio_set_comment(t_fileio *fio, const char *comment)
176 fio->comment = comment;
179 extern void gmx_fio_unset_comment(t_fileio *fio)
185 const char *gmx_fio_dbgstr(t_fileio *fio, const char *desc, char *buf)
189 /* set to empty string */
194 snprintf(buf, GMX_FIO_BUFLEN, " ; %s %s", fio->comment ? fio->comment : "", desc);
200 /* check the number of items given against the type */
201 void gmx_fio_check_nitem(t_fileio *fio, int eio, int nitem, const char *file,
204 if ((nitem != 1) && !((eio == eioNRVEC) || (eio == eioNUCHAR)))
207 "nitem (%d) may differ from 1 only for %s or %s, not for %s"
208 "(%s, %d)", nitem, eioNames[eioNUCHAR], eioNames[eioNRVEC],
209 eioNames[eio], file, line);
214 /* output a data type error. */
215 void gmx_fio_fe(t_fileio *fio, int eio, const char *desc,
216 const char *srcfile, int line)
219 gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d",
220 fio->bRead ? "read" : "write", desc, eio,
221 ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown",
226 /* set the reader/writer functions based on the file type */
227 static void gmx_fio_set_iotype(t_fileio *fio)
229 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
232 fio->iotp = &xdr_iotype;
234 gmx_fatal(FARGS, "Sorry, no XDR");
237 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
239 fio->iotp = &asc_iotype;
241 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
243 fio->iotp = &bin_iotype;
247 fio->iotp = &dummy_iotype;
252 /* lock the mutex associated with this fio. This needs to be done for every
253 type of access to the fio's elements. */
254 void gmx_fio_lock(t_fileio *fio)
256 #ifdef GMX_THREAD_MPI
257 tMPI_Lock_lock(&(fio->mtx));
260 /* unlock the mutex associated with this fio. */
261 void gmx_fio_unlock(t_fileio *fio)
263 #ifdef GMX_THREAD_MPI
264 tMPI_Lock_unlock(&(fio->mtx));
268 /* make a dummy head element, assuming we locked everything. */
269 static void gmx_fio_make_dummy(void)
274 open_files->fp = NULL;
275 open_files->fn = NULL;
276 open_files->next = open_files;
277 open_files->prev = open_files;
278 #ifdef GMX_THREAD_MPI
279 tMPI_Lock_init(&(open_files->mtx));
290 /***********************************************************************
292 * FILE LIST OPERATIONS
294 ***********************************************************************/
297 /* insert a new t_fileio into the list */
298 static void gmx_fio_insert(t_fileio *fio)
301 #ifdef GMX_THREAD_MPI
302 /* first lock the big open_files mutex. */
303 tMPI_Thread_mutex_lock(&open_file_mutex);
305 /* now check whether the dummy element has been allocated,
306 and allocate it if it hasn't */
307 gmx_fio_make_dummy();
309 /* and lock the fio we got and the list's head **/
311 gmx_fio_lock(open_files);
312 prev = open_files->prev;
313 /* lock the element after the current one */
314 if (prev != open_files)
319 /* now do the actual insertion: */
320 fio->next = open_files;
321 open_files->prev = fio;
325 /* now unlock all our locks */
326 if (prev != open_files)
328 gmx_fio_unlock(prev);
330 gmx_fio_unlock(open_files);
333 #ifdef GMX_THREAD_MPI
334 /* now unlock the big open_files mutex. */
335 tMPI_Thread_mutex_unlock(&open_file_mutex);
339 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
341 NOTE: We also assume that the open_file_mutex has been locked */
342 static void gmx_fio_remove(t_fileio *fio)
346 /* lock prev, because we're changing it */
347 gmx_fio_lock(fio->prev);
349 /* now set the prev's pointer */
350 fio->prev->next = fio->next;
351 gmx_fio_unlock(fio->prev);
353 /* with the next ptr, we can simply lock while the original was locked */
354 gmx_fio_lock(fio->next);
355 fio->next->prev = fio->prev;
356 gmx_fio_unlock(fio->next);
358 /* and make sure we point nowhere in particular */
359 fio->next = fio->prev = fio;
363 /* get the first open file, or NULL if there is none.
364 Returns a locked fio. */
365 static t_fileio *gmx_fio_get_first(void)
368 /* first lock the big open_files mutex and the dummy's mutex */
370 #ifdef GMX_THREAD_MPI
371 /* first lock the big open_files mutex. */
372 tMPI_Thread_mutex_lock(&open_file_mutex);
374 gmx_fio_make_dummy();
376 gmx_fio_lock(open_files);
377 ret = open_files->next;
380 /* check whether there were any to begin with */
381 if (ret == open_files)
383 /* after this, the open_file pointer should never change */
388 gmx_fio_lock(open_files->next);
390 gmx_fio_unlock(open_files);
396 /* get the next open file, or NULL if there is none.
397 Unlocks the previous fio and locks the next one. */
398 static t_fileio *gmx_fio_get_next(t_fileio *fio)
403 /* check if that was the last one */
404 if (fio->next == open_files)
407 #ifdef GMX_THREAD_MPI
408 tMPI_Thread_mutex_unlock(&open_file_mutex);
420 /* Stop looping through the open_files. Unlocks the global lock. */
421 static void gmx_fio_stop_getting_next(t_fileio *fio)
424 #ifdef GMX_THREAD_MPI
425 tMPI_Thread_mutex_unlock(&open_file_mutex);
432 /*****************************************************************
436 *****************************************************************/
437 t_fileio *gmx_fio_open(const char *fn, const char *mode)
439 t_fileio *fio = NULL;
442 gmx_bool bRead, bReadWrite;
445 if (fn2ftp(fn) == efTPA)
447 strcpy(newmode, mode);
451 /* sanitize the mode string */
452 if (strncmp(mode, "r+", 2) == 0)
454 strcpy(newmode, "r+");
456 else if (mode[0] == 'r')
458 strcpy(newmode, "r");
460 else if (strncmp(mode, "w+", 2) == 0)
462 strcpy(newmode, "w+");
464 else if (mode[0] == 'w')
466 strcpy(newmode, "w");
468 else if (strncmp(mode, "a+", 2) == 0)
470 strcpy(newmode, "a+");
472 else if (mode[0] == 'a')
474 strcpy(newmode, "a");
478 gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'", mode);
482 /* Check if it should be opened as a binary file */
483 if (strncmp(ftp2ftype(fn2ftp(fn)), "ASCII", 5))
485 /* Not ascii, add b to file mode */
486 if ((strchr(newmode, 'b') == NULL) && (strchr(newmode, 'B') == NULL))
488 strcat(newmode, "b");
493 #ifdef GMX_THREAD_MPI
494 tMPI_Lock_init(&(fio->mtx));
496 bRead = (newmode[0] == 'r' && newmode[1] != '+');
497 bReadWrite = (newmode[1] == '+');
502 fio->iFTP = fn2ftp(fn);
503 fio->fn = strdup(fn);
506 /* If this file type is in the list of XDR files, open it like that */
507 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
509 /* First check whether we have to make a backup,
510 * only for writing, not for read or append.
512 if (newmode[0] == 'w')
515 /* only make backups for normal gromacs */
521 /* Check whether file exists */
528 fio->fp = ffopen(fn, newmode);
530 /* determine the XDR direction */
531 if (newmode[0] == 'w' || newmode[0] == 'a')
533 fio->xdrmode = XDR_ENCODE;
537 fio->xdrmode = XDR_DECODE;
541 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
545 /* If it is not, open it as a regular file */
546 fio->fp = ffopen(fn, newmode);
549 /* for appending seek to end of file to make sure ftell gives correct position
550 * important for checkpointing */
551 if (newmode[0] == 'a')
553 gmx_fseek(fio->fp, 0, SEEK_END);
558 /* Use stdin/stdout for I/O */
560 fio->fp = bRead ? stdin : stdout;
561 fio->fn = strdup("STDIO");
565 fio->bReadWrite = bReadWrite;
566 fio->bDouble = (sizeof(real) == sizeof(double));
569 fio->bLargerThan_off_t = FALSE;
571 /* set the reader/writer functions */
572 gmx_fio_set_iotype(fio);
574 /* and now insert this file into the list of open files. */
579 static int gmx_fio_close_locked(t_fileio *fio)
585 gmx_fatal(FARGS, "File %s closed twice!\n", fio->fn);
588 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
590 xdr_destroy(fio->xdr);
594 /* Don't close stdin and stdout! */
595 if (!fio->bStdio && fio->fp != NULL)
597 rc = ffclose(fio->fp); /* fclose returns 0 if happy */
605 int gmx_fio_close(t_fileio *fio)
609 #ifdef GMX_THREAD_MPI
610 /* first lock the big open_files mutex. */
611 /* We don't want two processes operating on the list at the same time */
612 tMPI_Thread_mutex_lock(&open_file_mutex);
616 /* first remove it from the list */
618 rc = gmx_fio_close_locked(fio);
623 #ifdef GMX_THREAD_MPI
624 tMPI_Thread_mutex_unlock(&open_file_mutex);
630 /* close only fp but keep FIO entry. */
631 int gmx_fio_fp_close(t_fileio *fio)
635 if (!in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR) && !fio->bStdio)
637 rc = ffclose(fio->fp); /* fclose returns 0 if happy */
645 FILE * gmx_fio_fopen(const char *fn, const char *mode)
650 fio = gmx_fio_open(fn, mode);
658 int gmx_fio_fclose(FILE *fp)
661 t_fileio *found = NULL;
664 cur = gmx_fio_get_first();
669 rc = gmx_fio_close_locked(cur);
671 gmx_fio_stop_getting_next(cur);
674 cur = gmx_fio_get_next(cur);
680 /* internal variant of get_file_md5 that operates on a locked file */
681 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
682 unsigned char digest[])
684 /*1MB: large size important to catch almost identical files */
685 #define CPT_CHK_LEN 1048576
687 unsigned char buf[CPT_CHK_LEN];
689 gmx_off_t seek_offset;
692 seek_offset = offset - CPT_CHK_LEN;
697 read_len = offset - seek_offset;
700 if (fio->fp && fio->bReadWrite)
702 ret = gmx_fseek(fio->fp, seek_offset, SEEK_SET);
705 gmx_fseek(fio->fp, 0, SEEK_END);
708 if (ret) /*either no fp, not readwrite, or fseek not successful */
713 /* the read puts the file position back to offset */
714 if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
716 /* not fatal: md5sum check to prevent overwriting files
717 * works (less safe) without
721 fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
724 else if (feof(fio->fp))
727 * For long runs that checkpoint frequently but write e.g. logs
728 * infrequently we don't want to issue lots of warnings before we
729 * have written anything to the log.
733 fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
740 "\nTrying to get md5sum: Unknown reason for short read: %s\n",
744 gmx_fseek(fio->fp, 0, SEEK_END);
748 gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows
749 it gives problems otherwise*/
753 fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
759 md5_append(&state, buf, read_len);
760 md5_finish(&state, digest);
771 * fio: file to compute md5 for
772 * offset: starting pointer of region to use for md5
773 * digest: return array of md5 sum
775 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
776 unsigned char digest[])
781 ret = gmx_fio_int_get_file_md5(fio, offset, digest);
787 /* The fio_mutex should ALWAYS be locked when this function is called */
788 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
792 /* Flush the file, so we are sure it is written */
793 if (gmx_fio_int_flush(fio))
798 "Cannot write file '%s'; maybe you are out of disk space?",
803 /* We cannot count on XDR being able to write 64-bit integers,
804 so separate into high/low 32-bit values.
805 In case the filesystem has 128-bit offsets we only care
806 about the first 64 bits - we'll have to fix
807 this when exabyte-size output files are common...
809 *offset = gmx_ftell(fio->fp);
814 int gmx_fio_check_file_position(t_fileio *fio)
816 /* If gmx_off_t is 4 bytes we can not store file offset > 2 GB.
817 * If we do not have ftello, we will play it safe.
819 #if (SIZEOF_GMX_OFF_T == 4 || !defined HAVE_FSEEKO)
823 gmx_fio_int_get_file_position(fio, &offset);
824 /* We have a 4 byte offset,
825 * make sure that we will detect out of range for all possible cases.
827 if (offset < 0 || offset > 2147483647)
829 fio->bLargerThan_off_t = TRUE;
837 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
840 int i, nfiles, rc, nalloc;
843 gmx_file_position_t * outputfiles;
849 /* pre-allocate 100 files */
851 snew(outputfiles, nalloc);
853 cur = gmx_fio_get_first();
856 /* Skip the checkpoint files themselves, since they could be open when
857 we call this routine... */
858 /* also skip debug files (shoud be the only iFTP==efNR) */
862 cur->iFTP != efCPT &&
866 /* This is an output file currently open for writing, add it */
867 if (nfiles == nalloc)
870 srenew(outputfiles, nalloc);
873 strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
875 /* Get the file position */
876 if (cur->bLargerThan_off_t)
878 /* -1 signals out of range */
879 outputfiles[nfiles].offset = -1;
880 outputfiles[nfiles].chksum_size = -1;
884 gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
886 outputfiles[nfiles].chksum_size
887 = gmx_fio_int_get_file_md5(cur,
888 outputfiles[nfiles].offset,
889 outputfiles[nfiles].chksum);
896 cur = gmx_fio_get_next(cur);
899 *p_outputfiles = outputfiles;
905 void gmx_fio_checktype(t_fileio *fio)
907 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
911 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
915 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
921 gmx_fatal(FARGS, "Can not read/write topologies to file type %s",
928 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
931 fio->bDouble = bDouble;
935 gmx_bool gmx_fio_getdebug(t_fileio *fio)
946 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
949 fio->bDebug = bDebug;
953 char *gmx_fio_getname(t_fileio *fio)
963 int gmx_fio_getftp(t_fileio* fio)
974 void gmx_fio_rewind(t_fileio* fio)
980 xdr_destroy(fio->xdr);
982 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
992 int gmx_fio_flush(t_fileio* fio)
997 ret = gmx_fio_int_flush(fio);
1005 static int gmx_fio_int_fsync(t_fileio *fio)
1013 rc = gmx_fsync(fio->fp);
1015 else if (fio->xdr) /* this should normally not happen */
1017 rc = gmx_fsync((FILE*) fio->xdr->x_private);
1018 /* ^ is this actually OK? */
1025 int gmx_fio_fsync(t_fileio *fio)
1030 rc = gmx_fio_int_fsync(fio);
1031 gmx_fio_unlock(fio);
1038 t_fileio *gmx_fio_all_output_fsync(void)
1040 t_fileio *ret = NULL;
1043 cur = gmx_fio_get_first();
1046 /* skip debug files (shoud be the only iFTP==efNR) */
1052 /* if any of them fails, return failure code */
1053 int rc = gmx_fio_int_fsync(cur);
1054 if (rc != 0 && !ret)
1059 cur = gmx_fio_get_next(cur);
1062 /* in addition, we force these to be written out too, if they're being
1063 redirected. We don't check for errors because errors most likely mean
1064 that they're not redirected. */
1067 #if (defined(HAVE_FSYNC))
1068 /* again, fahcore defines HAVE_FSYNC and fsync() */
1069 fsync(STDOUT_FILENO);
1070 fsync(STDERR_FILENO);
1077 gmx_off_t gmx_fio_ftell(t_fileio* fio)
1084 ret = gmx_ftell(fio->fp);
1086 gmx_fio_unlock(fio);
1090 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
1097 rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
1104 gmx_fio_unlock(fio);
1108 FILE *gmx_fio_getfp(t_fileio *fio)
1117 gmx_fio_unlock(fio);
1121 XDR *gmx_fio_getxdr(t_fileio* fio)
1130 gmx_fio_unlock(fio);
1135 gmx_bool gmx_fio_getread(t_fileio* fio)
1141 gmx_fio_unlock(fio);
1146 int xtc_seek_frame(t_fileio *fio, int frame, int natoms)
1151 ret = xdr_xtc_seek_frame(frame, fio->fp, fio->xdr, natoms);
1152 gmx_fio_unlock(fio);
1157 int xtc_seek_time(t_fileio *fio, real time, int natoms, gmx_bool bSeekForwardOnly)
1162 ret = xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms, bSeekForwardOnly);
1163 gmx_fio_unlock(fio);