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, 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.
51 #include "gmx_fatal.h"
61 #include "thread_mpi.h"
64 #include "gmxfio_int.h"
66 /* This is the new improved and thread safe version of gmxfio. */
70 /* the list of open files is a linked list, with a dummy element at its head;
71 it is initialized when the first file is opened. */
72 static t_fileio *open_files = NULL;
76 /* this mutex locks the open_files structure so that no two threads can
79 For now, we use this as a coarse grained lock on all file
80 insertion/deletion operations because it makes avoiding deadlocks
81 easier, and adds almost no overhead: the only overhead is during
82 opening and closing of files, or during global operations like
83 iterating along all open files. All these cases should be rare
84 during the simulation. */
85 static tMPI_Thread_mutex_t open_file_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
89 /* These simple lists define the I/O type for these files */
90 static const int ftpXDR[] =
91 { efTPR, efTRR, efEDR, efXTC, efMTX, efCPT };
92 static const int ftpASC[] =
93 { efTPA, efGRO, efPDB };
94 static const int ftpBIN[] =
97 static const int ftpXML[] =
101 const char *itemstr[eitemNR] =
103 "[header]", "[inputrec]", "[box]", "[topology]", "[coordinates]",
104 "[velocities]", "[forces]"
107 const char *eioNames[eioNR] =
109 "REAL", "INT", "GMX_STE_T", "UCHAR", "NUCHAR", "USHORT", "RVEC", "NRVEC",
115 /* Comment strings for TPA only */
116 const char *comment_str[eitemNR] = {
117 "; The header holds information on the number of atoms etc. and on whether\n"
118 "; certain items are present in the file or not.\n"
121 "; DO NOT EDIT THIS FILE BY HAND\n"
122 "; The GROMACS preprocessor performs a lot of checks on your input that\n"
123 "; you ignore when editing this. Your simulation may crash because of this\n",
124 "; The inputrec holds the parameters for MD such as the number of steps,\n"
125 "; the timestep and the cut-offs.\n",
126 "; The simulation box in nm.\n",
127 "; The topology section describes the topology of the molecules\n"
128 "; i.e. bonds, angles and dihedrals etc. and also holds the force field\n"
130 "; The atomic coordinates in nm\n",
131 "; The atomic velocities in nm/ps\n",
132 "; The forces on the atoms in nm/ps^2\n"
138 /******************************************************************
140 * Internal functions:
142 ******************************************************************/
144 static int gmx_fio_int_flush(t_fileio* fio)
150 rc = fflush(fio->fp);
154 rc = fflush((FILE *) fio->xdr->x_private);
160 /* returns TRUE if the file type ftp is in the set set */
161 static gmx_bool in_ftpset(int ftp, int nset, const int set[])
167 for (i = 0; (i < nset); i++)
180 extern void gmx_fio_set_comment(t_fileio *fio, const char *comment)
182 fio->comment = comment;
185 extern void gmx_fio_unset_comment(t_fileio *fio)
191 const char *gmx_fio_dbgstr(t_fileio *fio, const char *desc, char *buf)
195 /* set to empty string */
200 snprintf(buf, GMX_FIO_BUFLEN, " ; %s %s", fio->comment ? fio->comment : "", desc);
206 /* check the number of items given against the type */
207 void gmx_fio_check_nitem(int eio, int nitem, const char *file, int line)
209 if ((nitem != 1) && !((eio == eioNRVEC) || (eio == eioNUCHAR)))
212 "nitem (%d) may differ from 1 only for %s or %s, not for %s"
213 "(%s, %d)", nitem, eioNames[eioNUCHAR], eioNames[eioNRVEC],
214 eioNames[eio], file, line);
219 /* output a data type error. */
220 void gmx_fio_fe(t_fileio *fio, int eio, const char *desc,
221 const char *srcfile, int line)
224 gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d",
225 fio->bRead ? "read" : "write", desc, eio,
226 ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown",
231 /* set the reader/writer functions based on the file type */
232 static void gmx_fio_set_iotype(t_fileio *fio)
234 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
237 fio->iotp = &xdr_iotype;
239 gmx_fatal(FARGS, "Sorry, no XDR");
242 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
244 fio->iotp = &asc_iotype;
246 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
248 fio->iotp = &bin_iotype;
251 else if (in_ftpset(fio->iFTP, asize(ftpXML), ftpXML))
253 fio->iotp = &dummy_iotype;
258 fio->iotp = &dummy_iotype;
263 /* lock the mutex associated with this fio. This needs to be done for every
264 type of access to the fio's elements. */
265 void gmx_fio_lock(t_fileio *fio)
267 #ifdef GMX_THREAD_MPI
268 tMPI_Lock_lock(&(fio->mtx));
271 /* unlock the mutex associated with this fio. */
272 void gmx_fio_unlock(t_fileio *fio)
274 #ifdef GMX_THREAD_MPI
275 tMPI_Lock_unlock(&(fio->mtx));
279 /* make a dummy head element, assuming we locked everything. */
280 static void gmx_fio_make_dummy(void)
285 open_files->fp = NULL;
286 open_files->fn = NULL;
287 open_files->next = open_files;
288 open_files->prev = open_files;
289 #ifdef GMX_THREAD_MPI
290 tMPI_Lock_init(&(open_files->mtx));
301 /***********************************************************************
303 * FILE LIST OPERATIONS
305 ***********************************************************************/
308 /* insert a new t_fileio into the list */
309 static void gmx_fio_insert(t_fileio *fio)
312 #ifdef GMX_THREAD_MPI
313 /* first lock the big open_files mutex. */
314 tMPI_Thread_mutex_lock(&open_file_mutex);
316 /* now check whether the dummy element has been allocated,
317 and allocate it if it hasn't */
318 gmx_fio_make_dummy();
320 /* and lock the fio we got and the list's head **/
322 gmx_fio_lock(open_files);
323 prev = open_files->prev;
324 /* lock the element after the current one */
325 if (prev != open_files)
330 /* now do the actual insertion: */
331 fio->next = open_files;
332 open_files->prev = fio;
336 /* now unlock all our locks */
337 if (prev != open_files)
339 gmx_fio_unlock(prev);
341 gmx_fio_unlock(open_files);
344 #ifdef GMX_THREAD_MPI
345 /* now unlock the big open_files mutex. */
346 tMPI_Thread_mutex_unlock(&open_file_mutex);
350 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
352 NOTE: We also assume that the open_file_mutex has been locked */
353 static void gmx_fio_remove(t_fileio *fio)
357 /* lock prev, because we're changing it */
358 gmx_fio_lock(fio->prev);
360 /* now set the prev's pointer */
361 fio->prev->next = fio->next;
362 gmx_fio_unlock(fio->prev);
364 /* with the next ptr, we can simply lock while the original was locked */
365 gmx_fio_lock(fio->next);
366 fio->next->prev = fio->prev;
367 gmx_fio_unlock(fio->next);
369 /* and make sure we point nowhere in particular */
370 fio->next = fio->prev = fio;
374 /* get the first open file, or NULL if there is none.
375 Returns a locked fio. */
376 static t_fileio *gmx_fio_get_first(void)
379 /* first lock the big open_files mutex and the dummy's mutex */
381 #ifdef GMX_THREAD_MPI
382 /* first lock the big open_files mutex. */
383 tMPI_Thread_mutex_lock(&open_file_mutex);
385 gmx_fio_make_dummy();
387 gmx_fio_lock(open_files);
388 ret = open_files->next;
391 /* check whether there were any to begin with */
392 if (ret == open_files)
394 /* after this, the open_file pointer should never change */
399 gmx_fio_lock(open_files->next);
401 gmx_fio_unlock(open_files);
407 /* get the next open file, or NULL if there is none.
408 Unlocks the previous fio and locks the next one. */
409 static t_fileio *gmx_fio_get_next(t_fileio *fio)
414 /* check if that was the last one */
415 if (fio->next == open_files)
418 #ifdef GMX_THREAD_MPI
419 tMPI_Thread_mutex_unlock(&open_file_mutex);
431 /* Stop looping through the open_files. Unlocks the global lock. */
432 static void gmx_fio_stop_getting_next(t_fileio *fio)
435 #ifdef GMX_THREAD_MPI
436 tMPI_Thread_mutex_unlock(&open_file_mutex);
443 /*****************************************************************
447 *****************************************************************/
448 t_fileio *gmx_fio_open(const char *fn, const char *mode)
450 t_fileio *fio = NULL;
453 gmx_bool bRead, bReadWrite;
456 if (fn2ftp(fn) == efTPA)
458 strcpy(newmode, mode);
462 /* sanitize the mode string */
463 if (strncmp(mode, "r+", 2) == 0)
465 strcpy(newmode, "r+");
467 else if (mode[0] == 'r')
469 strcpy(newmode, "r");
471 else if (strncmp(mode, "w+", 2) == 0)
473 strcpy(newmode, "w+");
475 else if (mode[0] == 'w')
477 strcpy(newmode, "w");
479 else if (strncmp(mode, "a+", 2) == 0)
481 strcpy(newmode, "a+");
483 else if (mode[0] == 'a')
485 strcpy(newmode, "a");
489 gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'", mode);
493 /* Check if it should be opened as a binary file */
494 if (strncmp(ftp2ftype(fn2ftp(fn)), "ASCII", 5))
496 /* Not ascii, add b to file mode */
497 if ((strchr(newmode, 'b') == NULL) && (strchr(newmode, 'B') == NULL))
499 strcat(newmode, "b");
504 #ifdef GMX_THREAD_MPI
505 tMPI_Lock_init(&(fio->mtx));
507 bRead = (newmode[0] == 'r' && newmode[1] != '+');
508 bReadWrite = (newmode[1] == '+');
513 fio->iFTP = fn2ftp(fn);
514 fio->fn = strdup(fn);
517 /* If this file type is in the list of XDR files, open it like that */
518 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
520 /* First check whether we have to make a backup,
521 * only for writing, not for read or append.
523 if (newmode[0] == 'w')
526 /* only make backups for normal gromacs */
532 /* Check whether file exists */
539 fio->fp = ffopen(fn, newmode);
541 /* determine the XDR direction */
542 if (newmode[0] == 'w' || newmode[0] == 'a')
544 fio->xdrmode = XDR_ENCODE;
548 fio->xdrmode = XDR_DECODE;
552 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
556 /* If it is not, open it as a regular file */
557 fio->fp = ffopen(fn, newmode);
560 /* for appending seek to end of file to make sure ftell gives correct position
561 * important for checkpointing */
562 if (newmode[0] == 'a')
564 gmx_fseek(fio->fp, 0, SEEK_END);
569 /* Use stdin/stdout for I/O */
571 fio->fp = bRead ? stdin : stdout;
572 fio->fn = strdup("STDIO");
576 fio->bReadWrite = bReadWrite;
577 fio->bDouble = (sizeof(real) == sizeof(double));
580 fio->bLargerThan_off_t = FALSE;
582 /* set the reader/writer functions */
583 gmx_fio_set_iotype(fio);
585 /* and now insert this file into the list of open files. */
590 static int gmx_fio_close_locked(t_fileio *fio)
596 gmx_fatal(FARGS, "File %s closed twice!\n", fio->fn);
599 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
601 xdr_destroy(fio->xdr);
605 /* Don't close stdin and stdout! */
606 if (!fio->bStdio && fio->fp != NULL)
608 rc = ffclose(fio->fp); /* fclose returns 0 if happy */
616 int gmx_fio_close(t_fileio *fio)
620 #ifdef GMX_THREAD_MPI
621 /* first lock the big open_files mutex. */
622 /* We don't want two processes operating on the list at the same time */
623 tMPI_Thread_mutex_lock(&open_file_mutex);
627 /* first remove it from the list */
629 rc = gmx_fio_close_locked(fio);
635 #ifdef GMX_THREAD_MPI
636 tMPI_Thread_mutex_unlock(&open_file_mutex);
642 /* close only fp but keep FIO entry. */
643 int gmx_fio_fp_close(t_fileio *fio)
647 if (!in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR) && !fio->bStdio)
649 rc = ffclose(fio->fp); /* fclose returns 0 if happy */
657 FILE * gmx_fio_fopen(const char *fn, const char *mode)
662 fio = gmx_fio_open(fn, mode);
670 int gmx_fio_fclose(FILE *fp)
673 t_fileio *found = NULL;
676 cur = gmx_fio_get_first();
681 rc = gmx_fio_close_locked(cur);
683 gmx_fio_stop_getting_next(cur);
688 cur = gmx_fio_get_next(cur);
694 /* internal variant of get_file_md5 that operates on a locked file */
695 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
696 unsigned char digest[])
698 /*1MB: large size important to catch almost identical files */
699 #define CPT_CHK_LEN 1048576
701 unsigned char buf[CPT_CHK_LEN];
703 gmx_off_t seek_offset;
706 seek_offset = offset - CPT_CHK_LEN;
711 read_len = offset - seek_offset;
714 if (fio->fp && fio->bReadWrite)
716 ret = gmx_fseek(fio->fp, seek_offset, SEEK_SET);
719 gmx_fseek(fio->fp, 0, SEEK_END);
722 if (ret) /*either no fp, not readwrite, or fseek not successful */
727 /* the read puts the file position back to offset */
728 if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
730 /* not fatal: md5sum check to prevent overwriting files
731 * works (less safe) without
735 fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
738 else if (feof(fio->fp))
741 * For long runs that checkpoint frequently but write e.g. logs
742 * infrequently we don't want to issue lots of warnings before we
743 * have written anything to the log.
747 fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
754 "\nTrying to get md5sum: Unknown reason for short read: %s\n",
758 gmx_fseek(fio->fp, 0, SEEK_END);
762 gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows
763 it gives problems otherwise*/
767 fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
773 md5_append(&state, buf, read_len);
774 md5_finish(&state, digest);
785 * fio: file to compute md5 for
786 * offset: starting pointer of region to use for md5
787 * digest: return array of md5 sum
789 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
790 unsigned char digest[])
795 ret = gmx_fio_int_get_file_md5(fio, offset, digest);
801 /* The fio_mutex should ALWAYS be locked when this function is called */
802 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
806 /* Flush the file, so we are sure it is written */
807 if (gmx_fio_int_flush(fio))
812 "Cannot write file '%s'; maybe you are out of disk space?",
817 /* We cannot count on XDR being able to write 64-bit integers,
818 so separate into high/low 32-bit values.
819 In case the filesystem has 128-bit offsets we only care
820 about the first 64 bits - we'll have to fix
821 this when exabyte-size output files are common...
823 *offset = gmx_ftell(fio->fp);
828 int gmx_fio_check_file_position(t_fileio gmx_unused *fio)
830 /* If gmx_off_t is 4 bytes we can not store file offset > 2 GB.
831 * If we do not have ftello, we will play it safe.
833 #if (SIZEOF_GMX_OFF_T == 4 || !defined HAVE_FSEEKO)
837 gmx_fio_int_get_file_position(fio, &offset);
838 /* We have a 4 byte offset,
839 * make sure that we will detect out of range for all possible cases.
841 if (offset < 0 || offset > 2147483647)
843 fio->bLargerThan_off_t = TRUE;
851 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
854 int i, nfiles, rc, nalloc;
857 gmx_file_position_t * outputfiles;
863 /* pre-allocate 100 files */
865 snew(outputfiles, nalloc);
867 cur = gmx_fio_get_first();
870 /* Skip the checkpoint files themselves, since they could be open when
871 we call this routine... */
872 /* also skip debug files (shoud be the only iFTP==efNR) */
876 cur->iFTP != efCPT &&
880 /* This is an output file currently open for writing, add it */
881 if (nfiles == nalloc)
884 srenew(outputfiles, nalloc);
887 strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
889 /* Get the file position */
890 if (cur->bLargerThan_off_t)
892 /* -1 signals out of range */
893 outputfiles[nfiles].offset = -1;
894 outputfiles[nfiles].chksum_size = -1;
898 gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
900 outputfiles[nfiles].chksum_size
901 = gmx_fio_int_get_file_md5(cur,
902 outputfiles[nfiles].offset,
903 outputfiles[nfiles].chksum);
910 cur = gmx_fio_get_next(cur);
913 *p_outputfiles = outputfiles;
919 void gmx_fio_checktype(t_fileio *fio)
921 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
925 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
929 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
934 else if (in_ftpset(fio->iFTP, asize(ftpXML), ftpXML))
941 gmx_fatal(FARGS, "Can not read/write topologies to file type %s",
948 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
951 fio->bDouble = bDouble;
955 gmx_bool gmx_fio_getdebug(t_fileio *fio)
966 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
969 fio->bDebug = bDebug;
973 char *gmx_fio_getname(t_fileio *fio)
983 int gmx_fio_getftp(t_fileio* fio)
994 void gmx_fio_rewind(t_fileio* fio)
1000 xdr_destroy(fio->xdr);
1002 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
1008 gmx_fio_unlock(fio);
1012 int gmx_fio_flush(t_fileio* fio)
1017 ret = gmx_fio_int_flush(fio);
1018 gmx_fio_unlock(fio);
1025 static int gmx_fio_int_fsync(t_fileio *fio)
1033 rc = gmx_fsync(fio->fp);
1035 else if (fio->xdr) /* this should normally not happen */
1037 rc = gmx_fsync((FILE*) fio->xdr->x_private);
1038 /* ^ is this actually OK? */
1045 int gmx_fio_fsync(t_fileio *fio)
1050 rc = gmx_fio_int_fsync(fio);
1051 gmx_fio_unlock(fio);
1058 t_fileio *gmx_fio_all_output_fsync(void)
1060 t_fileio *ret = NULL;
1063 cur = gmx_fio_get_first();
1066 /* skip debug files (shoud be the only iFTP==efNR) */
1072 /* if any of them fails, return failure code */
1073 int rc = gmx_fio_int_fsync(cur);
1074 if (rc != 0 && !ret)
1079 cur = gmx_fio_get_next(cur);
1082 /* in addition, we force these to be written out too, if they're being
1083 redirected. We don't check for errors because errors most likely mean
1084 that they're not redirected. */
1087 #if (defined(HAVE_FSYNC))
1088 /* again, fahcore defines HAVE_FSYNC and fsync() */
1089 fsync(STDOUT_FILENO);
1090 fsync(STDERR_FILENO);
1097 gmx_off_t gmx_fio_ftell(t_fileio* fio)
1104 ret = gmx_ftell(fio->fp);
1106 gmx_fio_unlock(fio);
1110 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
1117 rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
1124 gmx_fio_unlock(fio);
1128 FILE *gmx_fio_getfp(t_fileio *fio)
1137 gmx_fio_unlock(fio);
1141 XDR *gmx_fio_getxdr(t_fileio* fio)
1150 gmx_fio_unlock(fio);
1155 gmx_bool gmx_fio_getread(t_fileio* fio)
1161 gmx_fio_unlock(fio);
1166 int xtc_seek_frame(t_fileio *fio, int frame, int natoms)
1171 ret = xdr_xtc_seek_frame(frame, fio->fp, fio->xdr, natoms);
1172 gmx_fio_unlock(fio);
1177 int xtc_seek_time(t_fileio *fio, real time, int natoms, gmx_bool bSeekForwardOnly)
1182 ret = xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms, bSeekForwardOnly);
1183 gmx_fio_unlock(fio);