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.
49 #include "thread_mpi/threads.h"
51 #include "gromacs/utility/fatalerror.h"
53 #include "gromacs/utility/smalloc.h"
54 #include "gromacs/utility/futil.h"
56 #include "gromacs/utility/cstringutil.h"
60 #include "gmxfio_int.h"
62 /* This is the new improved and thread safe version of gmxfio. */
66 /* the list of open files is a linked list, with a dummy element at its head;
67 it is initialized when the first file is opened. */
68 static t_fileio *open_files = NULL;
71 /* this mutex locks the open_files structure so that no two threads can
74 For now, we use this as a coarse grained lock on all file
75 insertion/deletion operations because it makes avoiding deadlocks
76 easier, and adds almost no overhead: the only overhead is during
77 opening and closing of files, or during global operations like
78 iterating along all open files. All these cases should be rare
79 during the simulation. */
80 static tMPI_Thread_mutex_t open_file_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
83 /* These simple lists define the I/O type for these files */
84 static const int ftpXDR[] =
85 { efTPR, efTRR, efEDR, efXTC, efTNG, efMTX, efCPT };
86 static const int ftpASC[] =
87 { efTPA, efGRO, efPDB };
88 static const int ftpBIN[] =
89 { efTPB, efTRJ, efTNG };
91 static const int ftpXML[] =
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(int eio, int nitem, const char *file, int line)
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;
245 else if (in_ftpset(fio->iFTP, asize(ftpXML), ftpXML))
247 fio->iotp = &dummy_iotype;
252 fio->iotp = &dummy_iotype;
257 /* lock the mutex associated with this fio. This needs to be done for every
258 type of access to the fio's elements. */
259 void gmx_fio_lock(t_fileio *fio)
261 tMPI_Lock_lock(&(fio->mtx));
263 /* unlock the mutex associated with this fio. */
264 void gmx_fio_unlock(t_fileio *fio)
266 tMPI_Lock_unlock(&(fio->mtx));
269 /* make a dummy head element, assuming we locked everything. */
270 static void gmx_fio_make_dummy(void)
275 open_files->fp = NULL;
276 open_files->fn = NULL;
277 open_files->next = open_files;
278 open_files->prev = open_files;
279 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 /* first lock the big open_files mutex. */
301 tMPI_Thread_mutex_lock(&open_file_mutex);
302 /* now check whether the dummy element has been allocated,
303 and allocate it if it hasn't */
304 gmx_fio_make_dummy();
306 /* and lock the fio we got and the list's head **/
308 gmx_fio_lock(open_files);
309 prev = open_files->prev;
310 /* lock the element after the current one */
311 if (prev != open_files)
316 /* now do the actual insertion: */
317 fio->next = open_files;
318 open_files->prev = fio;
322 /* now unlock all our locks */
323 if (prev != open_files)
325 gmx_fio_unlock(prev);
327 gmx_fio_unlock(open_files);
330 /* now unlock the big open_files mutex. */
331 tMPI_Thread_mutex_unlock(&open_file_mutex);
334 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
336 NOTE: We also assume that the open_file_mutex has been locked */
337 static void gmx_fio_remove(t_fileio *fio)
341 /* lock prev, because we're changing it */
342 gmx_fio_lock(fio->prev);
344 /* now set the prev's pointer */
345 fio->prev->next = fio->next;
346 gmx_fio_unlock(fio->prev);
348 /* with the next ptr, we can simply lock while the original was locked */
349 gmx_fio_lock(fio->next);
350 fio->next->prev = fio->prev;
351 gmx_fio_unlock(fio->next);
353 /* and make sure we point nowhere in particular */
354 fio->next = fio->prev = fio;
358 /* get the first open file, or NULL if there is none.
359 Returns a locked fio. */
360 static t_fileio *gmx_fio_get_first(void)
363 /* first lock the big open_files mutex and the dummy's mutex */
365 /* first lock the big open_files mutex. */
366 tMPI_Thread_mutex_lock(&open_file_mutex);
367 gmx_fio_make_dummy();
369 gmx_fio_lock(open_files);
370 ret = open_files->next;
373 /* check whether there were any to begin with */
374 if (ret == open_files)
376 /* after this, the open_file pointer should never change */
381 gmx_fio_lock(open_files->next);
383 gmx_fio_unlock(open_files);
389 /* get the next open file, or NULL if there is none.
390 Unlocks the previous fio and locks the next one. */
391 static t_fileio *gmx_fio_get_next(t_fileio *fio)
396 /* check if that was the last one */
397 if (fio->next == open_files)
400 tMPI_Thread_mutex_unlock(&open_file_mutex);
411 /* Stop looping through the open_files. Unlocks the global lock. */
412 static void gmx_fio_stop_getting_next(t_fileio *fio)
415 tMPI_Thread_mutex_unlock(&open_file_mutex);
421 /*****************************************************************
425 *****************************************************************/
426 t_fileio *gmx_fio_open(const char *fn, const char *mode)
428 t_fileio *fio = NULL;
431 gmx_bool bRead, bReadWrite;
434 if (fn2ftp(fn) == efTPA)
436 strcpy(newmode, mode);
440 /* sanitize the mode string */
441 if (strncmp(mode, "r+", 2) == 0)
443 strcpy(newmode, "r+");
445 else if (mode[0] == 'r')
447 strcpy(newmode, "r");
449 else if (strncmp(mode, "w+", 2) == 0)
451 strcpy(newmode, "w+");
453 else if (mode[0] == 'w')
455 strcpy(newmode, "w");
457 else if (strncmp(mode, "a+", 2) == 0)
459 strcpy(newmode, "a+");
461 else if (mode[0] == 'a')
463 strcpy(newmode, "a");
467 gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'", mode);
471 /* Check if it should be opened as a binary file */
472 if (strncmp(ftp2ftype(fn2ftp(fn)), "ASCII", 5))
474 /* Not ascii, add b to file mode */
475 if ((strchr(newmode, 'b') == NULL) && (strchr(newmode, 'B') == NULL))
477 strcat(newmode, "b");
482 tMPI_Lock_init(&(fio->mtx));
483 bRead = (newmode[0] == 'r' && newmode[1] != '+');
484 bReadWrite = (newmode[1] == '+');
489 fio->iFTP = fn2ftp(fn);
490 fio->fn = gmx_strdup(fn);
493 /* If this file type is in the list of XDR files, open it like that */
494 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
496 /* First check whether we have to make a backup,
497 * only for writing, not for read or append.
499 if (newmode[0] == 'w')
502 /* only make backups for normal gromacs */
508 /* Check whether file exists */
514 if (fn2ftp(fn) == efTNG)
516 gmx_incons("gmx_fio_open may not be used to open TNG files");
519 fio->fp = gmx_ffopen(fn, newmode);
521 /* determine the XDR direction */
522 if (newmode[0] == 'w' || newmode[0] == 'a')
524 fio->xdrmode = XDR_ENCODE;
528 fio->xdrmode = XDR_DECODE;
532 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
536 /* If it is not, open it as a regular file */
537 fio->fp = gmx_ffopen(fn, newmode);
540 /* for appending seek to end of file to make sure ftell gives correct position
541 * important for checkpointing */
542 if (newmode[0] == 'a')
544 gmx_fseek(fio->fp, 0, SEEK_END);
549 /* Use stdin/stdout for I/O */
551 fio->fp = bRead ? stdin : stdout;
552 fio->fn = gmx_strdup("STDIO");
556 fio->bReadWrite = bReadWrite;
557 fio->bDouble = (sizeof(real) == sizeof(double));
561 /* set the reader/writer functions */
562 gmx_fio_set_iotype(fio);
564 /* and now insert this file into the list of open files. */
569 static int gmx_fio_close_locked(t_fileio *fio)
575 gmx_fatal(FARGS, "File %s closed twice!\n", fio->fn);
578 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
580 xdr_destroy(fio->xdr);
584 /* Don't close stdin and stdout! */
585 if (!fio->bStdio && fio->fp != NULL)
587 rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
595 int gmx_fio_close(t_fileio *fio)
599 /* first lock the big open_files mutex. */
600 /* We don't want two processes operating on the list at the same time */
601 tMPI_Thread_mutex_lock(&open_file_mutex);
603 if (fio->iFTP == efTNG)
605 gmx_incons("gmx_fio_close should not be called on a TNG file");
608 /* first remove it from the list */
610 rc = gmx_fio_close_locked(fio);
616 tMPI_Thread_mutex_unlock(&open_file_mutex);
621 /* close only fp but keep FIO entry. */
622 int gmx_fio_fp_close(t_fileio *fio)
626 if (!in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR) && !fio->bStdio)
628 rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
636 FILE * gmx_fio_fopen(const char *fn, const char *mode)
641 fio = gmx_fio_open(fn, mode);
649 int gmx_fio_fclose(FILE *fp)
652 t_fileio *found = NULL;
655 cur = gmx_fio_get_first();
660 rc = gmx_fio_close_locked(cur);
662 gmx_fio_stop_getting_next(cur);
667 cur = gmx_fio_get_next(cur);
673 /* internal variant of get_file_md5 that operates on a locked file */
674 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
675 unsigned char digest[])
677 /*1MB: large size important to catch almost identical files */
678 #define CPT_CHK_LEN 1048576
682 gmx_off_t seek_offset;
685 seek_offset = offset - CPT_CHK_LEN;
690 read_len = offset - seek_offset;
693 if (fio->fp && fio->bReadWrite)
695 ret = gmx_fseek(fio->fp, seek_offset, SEEK_SET);
698 gmx_fseek(fio->fp, 0, SEEK_END);
701 if (ret) /*either no fp, not readwrite, or fseek not successful */
706 snew(buf, CPT_CHK_LEN);
707 /* the read puts the file position back to offset */
708 if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
710 /* not fatal: md5sum check to prevent overwriting files
711 * works (less safe) without
715 fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
718 else if (feof(fio->fp))
721 * For long runs that checkpoint frequently but write e.g. logs
722 * infrequently we don't want to issue lots of warnings before we
723 * have written anything to the log.
727 fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
734 "\nTrying to get md5sum: Unknown reason for short read: %s\n",
738 gmx_fseek(fio->fp, 0, SEEK_END);
742 gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows
743 it gives problems otherwise*/
747 fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
752 gmx_md5_init(&state);
753 gmx_md5_append(&state, buf, read_len);
754 gmx_md5_finish(&state, digest);
763 * fio: file to compute md5 for
764 * offset: starting pointer of region to use for md5
765 * digest: return array of md5 sum
767 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
768 unsigned char digest[])
773 ret = gmx_fio_int_get_file_md5(fio, offset, digest);
779 /* The fio_mutex should ALWAYS be locked when this function is called */
780 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
784 /* Flush the file, so we are sure it is written */
785 if (gmx_fio_int_flush(fio))
790 "Cannot write file '%s'; maybe you are out of disk space?",
795 /* We cannot count on XDR being able to write 64-bit integers,
796 so separate into high/low 32-bit values.
797 In case the filesystem has 128-bit offsets we only care
798 about the first 64 bits - we'll have to fix
799 this when exabyte-size output files are common...
801 *offset = gmx_ftell(fio->fp);
806 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
809 int i, nfiles, rc, nalloc;
812 gmx_file_position_t * outputfiles;
818 /* pre-allocate 100 files */
820 snew(outputfiles, nalloc);
822 cur = gmx_fio_get_first();
825 /* Skip the checkpoint files themselves, since they could be open when
826 we call this routine... */
827 /* also skip debug files (shoud be the only iFTP==efNR) */
831 cur->iFTP != efCPT &&
835 /* This is an output file currently open for writing, add it */
836 if (nfiles == nalloc)
839 srenew(outputfiles, nalloc);
842 strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
844 /* Get the file position */
845 gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
847 outputfiles[nfiles].chksum_size
848 = gmx_fio_int_get_file_md5(cur,
849 outputfiles[nfiles].offset,
850 outputfiles[nfiles].chksum);
855 cur = gmx_fio_get_next(cur);
858 *p_outputfiles = outputfiles;
864 void gmx_fio_checktype(t_fileio *fio)
866 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
870 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
874 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
879 else if (in_ftpset(fio->iFTP, asize(ftpXML), ftpXML))
886 gmx_fatal(FARGS, "Can not read/write topologies to file type %s",
893 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
896 fio->bDouble = bDouble;
900 gmx_bool gmx_fio_getdebug(t_fileio *fio)
911 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
914 fio->bDebug = bDebug;
918 char *gmx_fio_getname(t_fileio *fio)
928 int gmx_fio_getftp(t_fileio* fio)
939 void gmx_fio_rewind(t_fileio* fio)
945 xdr_destroy(fio->xdr);
947 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
957 int gmx_fio_flush(t_fileio* fio)
962 ret = gmx_fio_int_flush(fio);
970 static int gmx_fio_int_fsync(t_fileio *fio)
978 rc = gmx_fsync(fio->fp);
980 else if (fio->xdr) /* this should normally not happen */
982 rc = gmx_fsync((FILE*) fio->xdr->x_private);
983 /* ^ is this actually OK? */
990 int gmx_fio_fsync(t_fileio *fio)
995 rc = gmx_fio_int_fsync(fio);
1003 t_fileio *gmx_fio_all_output_fsync(void)
1005 t_fileio *ret = NULL;
1008 cur = gmx_fio_get_first();
1011 /* skip debug files (shoud be the only iFTP==efNR) */
1017 /* if any of them fails, return failure code */
1018 int rc = gmx_fio_int_fsync(cur);
1019 if (rc != 0 && !ret)
1024 cur = gmx_fio_get_next(cur);
1027 /* in addition, we force these to be written out too, if they're being
1028 redirected. We don't check for errors because errors most likely mean
1029 that they're not redirected. */
1032 #if (defined(HAVE_FSYNC))
1033 /* again, fahcore defines HAVE_FSYNC and fsync() */
1034 fsync(STDOUT_FILENO);
1035 fsync(STDERR_FILENO);
1042 gmx_off_t gmx_fio_ftell(t_fileio* fio)
1049 ret = gmx_ftell(fio->fp);
1051 gmx_fio_unlock(fio);
1055 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
1062 rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
1069 gmx_fio_unlock(fio);
1073 FILE *gmx_fio_getfp(t_fileio *fio)
1082 gmx_fio_unlock(fio);
1086 XDR *gmx_fio_getxdr(t_fileio* fio)
1095 gmx_fio_unlock(fio);
1100 gmx_bool gmx_fio_getread(t_fileio* fio)
1106 gmx_fio_unlock(fio);
1111 int xtc_seek_frame(t_fileio *fio, int frame, int natoms)
1116 ret = xdr_xtc_seek_frame(frame, fio->fp, fio->xdr, natoms);
1117 gmx_fio_unlock(fio);
1122 int xtc_seek_time(t_fileio *fio, real time, int natoms, gmx_bool bSeekForwardOnly)
1127 ret = xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms, bSeekForwardOnly);
1128 gmx_fio_unlock(fio);