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.
48 #include "gmx_fatal.h"
58 #include "thread_mpi.h"
61 #include "gmxfio_int.h"
63 /* This is the new improved and thread safe version of gmxfio. */
67 /* the list of open files is a linked list, with a dummy element at its head;
68 it is initialized when the first file is opened. */
69 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;
86 /* These simple lists define the I/O type for these files */
87 static const int ftpXDR[] =
88 { efTPR, efTRR, efEDR, efXTC, efMTX, efCPT };
89 static const int ftpASC[] =
90 { efTPA, efGRO, efPDB };
91 static const int ftpBIN[] =
94 const char *itemstr[eitemNR] =
96 "[header]", "[inputrec]", "[box]", "[topology]", "[coordinates]",
97 "[velocities]", "[forces]"
100 const char *eioNames[eioNR] =
102 "REAL", "INT", "GMX_STE_T", "UCHAR", "NUCHAR", "USHORT", "RVEC", "NRVEC",
108 /* Comment strings for TPA only */
109 const char *comment_str[eitemNR] = {
110 "; The header holds information on the number of atoms etc. and on whether\n"
111 "; certain items are present in the file or not.\n"
114 "; DO NOT EDIT THIS FILE BY HAND\n"
115 "; The GROMACS preprocessor performs a lot of checks on your input that\n"
116 "; you ignore when editing this. Your simulation may crash because of this\n",
117 "; The inputrec holds the parameters for MD such as the number of steps,\n"
118 "; the timestep and the cut-offs.\n",
119 "; The simulation box in nm.\n",
120 "; The topology section describes the topology of the molecules\n"
121 "; i.e. bonds, angles and dihedrals etc. and also holds the force field\n"
123 "; The atomic coordinates in nm\n",
124 "; The atomic velocities in nm/ps\n",
125 "; The forces on the atoms in nm/ps^2\n"
131 /******************************************************************
133 * Internal functions:
135 ******************************************************************/
137 static int gmx_fio_int_flush(t_fileio* fio)
143 rc = fflush(fio->fp);
147 rc = fflush((FILE *) fio->xdr->x_private);
153 /* returns TRUE if the file type ftp is in the set set */
154 static gmx_bool in_ftpset(int ftp, int nset, const int set[])
160 for (i = 0; (i < nset); i++)
173 extern void gmx_fio_set_comment(t_fileio *fio, const char *comment)
175 fio->comment = comment;
178 extern void gmx_fio_unset_comment(t_fileio *fio)
184 const char *gmx_fio_dbgstr(t_fileio *fio, const char *desc, char *buf)
188 /* set to empty string */
193 snprintf(buf, GMX_FIO_BUFLEN, " ; %s %s", fio->comment ? fio->comment : "", desc);
199 /* check the number of items given against the type */
200 void gmx_fio_check_nitem(t_fileio *fio, int eio, int nitem, const char *file,
203 if ((nitem != 1) && !((eio == eioNRVEC) || (eio == eioNUCHAR)))
206 "nitem (%d) may differ from 1 only for %s or %s, not for %s"
207 "(%s, %d)", nitem, eioNames[eioNUCHAR], eioNames[eioNRVEC],
208 eioNames[eio], file, line);
213 /* output a data type error. */
214 void gmx_fio_fe(t_fileio *fio, int eio, const char *desc,
215 const char *srcfile, int line)
218 gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d",
219 fio->bRead ? "read" : "write", desc, eio,
220 ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown",
225 /* set the reader/writer functions based on the file type */
226 static void gmx_fio_set_iotype(t_fileio *fio)
228 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
231 fio->iotp = &xdr_iotype;
233 gmx_fatal(FARGS, "Sorry, no XDR");
236 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
238 fio->iotp = &asc_iotype;
240 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
242 fio->iotp = &bin_iotype;
246 fio->iotp = &dummy_iotype;
251 /* lock the mutex associated with this fio. This needs to be done for every
252 type of access to the fio's elements. */
253 void gmx_fio_lock(t_fileio *fio)
255 #ifdef GMX_THREAD_MPI
256 tMPI_Lock_lock(&(fio->mtx));
259 /* unlock the mutex associated with this fio. */
260 void gmx_fio_unlock(t_fileio *fio)
262 #ifdef GMX_THREAD_MPI
263 tMPI_Lock_unlock(&(fio->mtx));
267 /* make a dummy head element, assuming we locked everything. */
268 static void gmx_fio_make_dummy(void)
273 open_files->fp = NULL;
274 open_files->fn = NULL;
275 open_files->next = open_files;
276 open_files->prev = open_files;
277 #ifdef GMX_THREAD_MPI
278 tMPI_Lock_init(&(open_files->mtx));
289 /***********************************************************************
291 * FILE LIST OPERATIONS
293 ***********************************************************************/
296 /* insert a new t_fileio into the list */
297 static void gmx_fio_insert(t_fileio *fio)
300 #ifdef GMX_THREAD_MPI
301 /* first lock the big open_files mutex. */
302 tMPI_Thread_mutex_lock(&open_file_mutex);
304 /* now check whether the dummy element has been allocated,
305 and allocate it if it hasn't */
306 gmx_fio_make_dummy();
308 /* and lock the fio we got and the list's head **/
310 gmx_fio_lock(open_files);
311 prev = open_files->prev;
312 /* lock the element after the current one */
313 if (prev != open_files)
318 /* now do the actual insertion: */
319 fio->next = open_files;
320 open_files->prev = fio;
324 /* now unlock all our locks */
325 if (prev != open_files)
327 gmx_fio_unlock(prev);
329 gmx_fio_unlock(open_files);
332 #ifdef GMX_THREAD_MPI
333 /* now unlock the big open_files mutex. */
334 tMPI_Thread_mutex_unlock(&open_file_mutex);
338 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
340 NOTE: We also assume that the open_file_mutex has been locked */
341 static void gmx_fio_remove(t_fileio *fio)
345 /* lock prev, because we're changing it */
346 gmx_fio_lock(fio->prev);
348 /* now set the prev's pointer */
349 fio->prev->next = fio->next;
350 gmx_fio_unlock(fio->prev);
352 /* with the next ptr, we can simply lock while the original was locked */
353 gmx_fio_lock(fio->next);
354 fio->next->prev = fio->prev;
355 gmx_fio_unlock(fio->next);
357 /* and make sure we point nowhere in particular */
358 fio->next = fio->prev = fio;
362 /* get the first open file, or NULL if there is none.
363 Returns a locked fio. */
364 static t_fileio *gmx_fio_get_first(void)
367 /* first lock the big open_files mutex and the dummy's mutex */
369 #ifdef GMX_THREAD_MPI
370 /* first lock the big open_files mutex. */
371 tMPI_Thread_mutex_lock(&open_file_mutex);
373 gmx_fio_make_dummy();
375 gmx_fio_lock(open_files);
376 ret = open_files->next;
379 /* check whether there were any to begin with */
380 if (ret == open_files)
382 /* after this, the open_file pointer should never change */
387 gmx_fio_lock(open_files->next);
389 gmx_fio_unlock(open_files);
395 /* get the next open file, or NULL if there is none.
396 Unlocks the previous fio and locks the next one. */
397 static t_fileio *gmx_fio_get_next(t_fileio *fio)
402 /* check if that was the last one */
403 if (fio->next == open_files)
406 #ifdef GMX_THREAD_MPI
407 tMPI_Thread_mutex_unlock(&open_file_mutex);
419 /* Stop looping through the open_files. Unlocks the global lock. */
420 static void gmx_fio_stop_getting_next(t_fileio *fio)
423 #ifdef GMX_THREAD_MPI
424 tMPI_Thread_mutex_unlock(&open_file_mutex);
431 /*****************************************************************
435 *****************************************************************/
436 t_fileio *gmx_fio_open(const char *fn, const char *mode)
438 t_fileio *fio = NULL;
441 gmx_bool bRead, bReadWrite;
444 if (fn2ftp(fn) == efTPA)
446 strcpy(newmode, mode);
450 /* sanitize the mode string */
451 if (strncmp(mode, "r+", 2) == 0)
453 strcpy(newmode, "r+");
455 else if (mode[0] == 'r')
457 strcpy(newmode, "r");
459 else if (strncmp(mode, "w+", 2) == 0)
461 strcpy(newmode, "w+");
463 else if (mode[0] == 'w')
465 strcpy(newmode, "w");
467 else if (strncmp(mode, "a+", 2) == 0)
469 strcpy(newmode, "a+");
471 else if (mode[0] == 'a')
473 strcpy(newmode, "a");
477 gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'", mode);
481 /* Check if it should be opened as a binary file */
482 if (strncmp(ftp2ftype(fn2ftp(fn)), "ASCII", 5))
484 /* Not ascii, add b to file mode */
485 if ((strchr(newmode, 'b') == NULL) && (strchr(newmode, 'B') == NULL))
487 strcat(newmode, "b");
492 #ifdef GMX_THREAD_MPI
493 tMPI_Lock_init(&(fio->mtx));
495 bRead = (newmode[0] == 'r' && newmode[1] != '+');
496 bReadWrite = (newmode[1] == '+');
501 fio->iFTP = fn2ftp(fn);
502 fio->fn = strdup(fn);
505 /* If this file type is in the list of XDR files, open it like that */
506 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
508 /* First check whether we have to make a backup,
509 * only for writing, not for read or append.
511 if (newmode[0] == 'w')
514 /* only make backups for normal gromacs */
520 /* Check whether file exists */
527 fio->fp = ffopen(fn, newmode);
529 /* determine the XDR direction */
530 if (newmode[0] == 'w' || newmode[0] == 'a')
532 fio->xdrmode = XDR_ENCODE;
536 fio->xdrmode = XDR_DECODE;
540 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
544 /* If it is not, open it as a regular file */
545 fio->fp = ffopen(fn, newmode);
548 /* for appending seek to end of file to make sure ftell gives correct position
549 * important for checkpointing */
550 if (newmode[0] == 'a')
552 gmx_fseek(fio->fp, 0, SEEK_END);
557 /* Use stdin/stdout for I/O */
559 fio->fp = bRead ? stdin : stdout;
560 fio->fn = strdup("STDIO");
564 fio->bReadWrite = bReadWrite;
565 fio->bDouble = (sizeof(real) == sizeof(double));
568 fio->bLargerThan_off_t = FALSE;
570 /* set the reader/writer functions */
571 gmx_fio_set_iotype(fio);
573 /* and now insert this file into the list of open files. */
578 static int gmx_fio_close_locked(t_fileio *fio)
584 gmx_fatal(FARGS, "File %s closed twice!\n", fio->fn);
587 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
589 xdr_destroy(fio->xdr);
593 /* Don't close stdin and stdout! */
594 if (!fio->bStdio && fio->fp != NULL)
596 rc = ffclose(fio->fp); /* fclose returns 0 if happy */
604 int gmx_fio_close(t_fileio *fio)
608 #ifdef GMX_THREAD_MPI
609 /* first lock the big open_files mutex. */
610 /* We don't want two processes operating on the list at the same time */
611 tMPI_Thread_mutex_lock(&open_file_mutex);
615 /* first remove it from the list */
617 rc = gmx_fio_close_locked(fio);
622 #ifdef GMX_THREAD_MPI
623 tMPI_Thread_mutex_unlock(&open_file_mutex);
629 /* close only fp but keep FIO entry. */
630 int gmx_fio_fp_close(t_fileio *fio)
634 if (!in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR) && !fio->bStdio)
636 rc = ffclose(fio->fp); /* fclose returns 0 if happy */
644 FILE * gmx_fio_fopen(const char *fn, const char *mode)
649 fio = gmx_fio_open(fn, mode);
657 int gmx_fio_fclose(FILE *fp)
660 t_fileio *found = NULL;
663 cur = gmx_fio_get_first();
668 rc = gmx_fio_close_locked(cur);
670 gmx_fio_stop_getting_next(cur);
673 cur = gmx_fio_get_next(cur);
679 /* internal variant of get_file_md5 that operates on a locked file */
680 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
681 unsigned char digest[])
683 /*1MB: large size important to catch almost identical files */
684 #define CPT_CHK_LEN 1048576
688 gmx_off_t seek_offset;
691 seek_offset = offset - CPT_CHK_LEN;
696 read_len = offset - seek_offset;
699 if (fio->fp && fio->bReadWrite)
701 ret = gmx_fseek(fio->fp, seek_offset, SEEK_SET);
704 gmx_fseek(fio->fp, 0, SEEK_END);
707 if (ret) /*either no fp, not readwrite, or fseek not successful */
712 snew(buf, CPT_CHK_LEN);
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);
769 * fio: file to compute md5 for
770 * offset: starting pointer of region to use for md5
771 * digest: return array of md5 sum
773 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
774 unsigned char digest[])
779 ret = gmx_fio_int_get_file_md5(fio, offset, digest);
785 /* The fio_mutex should ALWAYS be locked when this function is called */
786 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
790 /* Flush the file, so we are sure it is written */
791 if (gmx_fio_int_flush(fio))
796 "Cannot write file '%s'; maybe you are out of disk space?",
801 /* We cannot count on XDR being able to write 64-bit integers,
802 so separate into high/low 32-bit values.
803 In case the filesystem has 128-bit offsets we only care
804 about the first 64 bits - we'll have to fix
805 this when exabyte-size output files are common...
807 *offset = gmx_ftell(fio->fp);
812 int gmx_fio_check_file_position(t_fileio *fio)
814 /* If gmx_off_t is 4 bytes we can not store file offset > 2 GB.
815 * If we do not have ftello, we will play it safe.
817 #if (SIZEOF_GMX_OFF_T == 4 || !defined HAVE_FSEEKO)
821 gmx_fio_int_get_file_position(fio, &offset);
822 /* We have a 4 byte offset,
823 * make sure that we will detect out of range for all possible cases.
825 if (offset < 0 || offset > 2147483647)
827 fio->bLargerThan_off_t = TRUE;
835 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
838 int i, nfiles, rc, nalloc;
841 gmx_file_position_t * outputfiles;
847 /* pre-allocate 100 files */
849 snew(outputfiles, nalloc);
851 cur = gmx_fio_get_first();
854 /* Skip the checkpoint files themselves, since they could be open when
855 we call this routine... */
856 /* also skip debug files (shoud be the only iFTP==efNR) */
860 cur->iFTP != efCPT &&
864 /* This is an output file currently open for writing, add it */
865 if (nfiles == nalloc)
868 srenew(outputfiles, nalloc);
871 strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
873 /* Get the file position */
874 if (cur->bLargerThan_off_t)
876 /* -1 signals out of range */
877 outputfiles[nfiles].offset = -1;
878 outputfiles[nfiles].chksum_size = -1;
882 gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
884 outputfiles[nfiles].chksum_size
885 = gmx_fio_int_get_file_md5(cur,
886 outputfiles[nfiles].offset,
887 outputfiles[nfiles].chksum);
894 cur = gmx_fio_get_next(cur);
897 *p_outputfiles = outputfiles;
903 void gmx_fio_checktype(t_fileio *fio)
905 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
909 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
913 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
919 gmx_fatal(FARGS, "Can not read/write topologies to file type %s",
926 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
929 fio->bDouble = bDouble;
933 gmx_bool gmx_fio_getdebug(t_fileio *fio)
944 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
947 fio->bDebug = bDebug;
951 char *gmx_fio_getname(t_fileio *fio)
961 int gmx_fio_getftp(t_fileio* fio)
972 void gmx_fio_rewind(t_fileio* fio)
978 xdr_destroy(fio->xdr);
980 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
990 int gmx_fio_flush(t_fileio* fio)
995 ret = gmx_fio_int_flush(fio);
1003 static int gmx_fio_int_fsync(t_fileio *fio)
1011 rc = gmx_fsync(fio->fp);
1013 else if (fio->xdr) /* this should normally not happen */
1015 rc = gmx_fsync((FILE*) fio->xdr->x_private);
1016 /* ^ is this actually OK? */
1023 int gmx_fio_fsync(t_fileio *fio)
1028 rc = gmx_fio_int_fsync(fio);
1029 gmx_fio_unlock(fio);
1036 t_fileio *gmx_fio_all_output_fsync(void)
1038 t_fileio *ret = NULL;
1041 cur = gmx_fio_get_first();
1044 /* skip debug files (shoud be the only iFTP==efNR) */
1050 /* if any of them fails, return failure code */
1051 int rc = gmx_fio_int_fsync(cur);
1052 if (rc != 0 && !ret)
1057 cur = gmx_fio_get_next(cur);
1060 /* in addition, we force these to be written out too, if they're being
1061 redirected. We don't check for errors because errors most likely mean
1062 that they're not redirected. */
1065 #if (defined(HAVE_FSYNC))
1066 /* again, fahcore defines HAVE_FSYNC and fsync() */
1067 fsync(STDOUT_FILENO);
1068 fsync(STDERR_FILENO);
1075 gmx_off_t gmx_fio_ftell(t_fileio* fio)
1082 ret = gmx_ftell(fio->fp);
1084 gmx_fio_unlock(fio);
1088 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
1095 rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
1102 gmx_fio_unlock(fio);
1106 FILE *gmx_fio_getfp(t_fileio *fio)
1115 gmx_fio_unlock(fio);
1119 XDR *gmx_fio_getxdr(t_fileio* fio)
1128 gmx_fio_unlock(fio);
1133 gmx_bool gmx_fio_getread(t_fileio* fio)
1139 gmx_fio_unlock(fio);
1144 int xtc_seek_frame(t_fileio *fio, int frame, int natoms)
1149 ret = xdr_xtc_seek_frame(frame, fio->fp, fio->xdr, natoms);
1150 gmx_fio_unlock(fio);
1155 int xtc_seek_time(t_fileio *fio, real time, int natoms, gmx_bool bSeekForwardOnly)
1160 ret = xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms, bSeekForwardOnly);
1161 gmx_fio_unlock(fio);