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.
51 #include "thread_mpi/threads.h"
53 #include "gmx_fatal.h"
55 #include "gromacs/utility/smalloc.h"
58 #include "gromacs/utility/cstringutil.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;
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;
85 /* These simple lists define the I/O type for these files */
86 static const int ftpXDR[] =
87 { efTPR, efTRR, efEDR, efXTC, efTNG, efMTX, efCPT };
88 static const int ftpASC[] =
89 { efTPA, efGRO, efPDB };
90 static const int ftpBIN[] =
91 { efTPB, efTRJ, efTNG };
93 static const int ftpXML[] =
97 const char *itemstr[eitemNR] =
99 "[header]", "[inputrec]", "[box]", "[topology]", "[coordinates]",
100 "[velocities]", "[forces]"
103 const char *eioNames[eioNR] =
105 "REAL", "INT", "GMX_STE_T", "UCHAR", "NUCHAR", "USHORT", "RVEC", "NRVEC",
111 /* Comment strings for TPA only */
112 const char *comment_str[eitemNR] = {
113 "; The header holds information on the number of atoms etc. and on whether\n"
114 "; certain items are present in the file or not.\n"
117 "; DO NOT EDIT THIS FILE BY HAND\n"
118 "; The GROMACS preprocessor performs a lot of checks on your input that\n"
119 "; you ignore when editing this. Your simulation may crash because of this\n",
120 "; The inputrec holds the parameters for MD such as the number of steps,\n"
121 "; the timestep and the cut-offs.\n",
122 "; The simulation box in nm.\n",
123 "; The topology section describes the topology of the molecules\n"
124 "; i.e. bonds, angles and dihedrals etc. and also holds the force field\n"
126 "; The atomic coordinates in nm\n",
127 "; The atomic velocities in nm/ps\n",
128 "; The forces on the atoms in nm/ps^2\n"
134 /******************************************************************
136 * Internal functions:
138 ******************************************************************/
140 static int gmx_fio_int_flush(t_fileio* fio)
146 rc = fflush(fio->fp);
150 rc = fflush((FILE *) fio->xdr->x_private);
156 /* returns TRUE if the file type ftp is in the set set */
157 static gmx_bool in_ftpset(int ftp, int nset, const int set[])
163 for (i = 0; (i < nset); i++)
176 extern void gmx_fio_set_comment(t_fileio *fio, const char *comment)
178 fio->comment = comment;
181 extern void gmx_fio_unset_comment(t_fileio *fio)
187 const char *gmx_fio_dbgstr(t_fileio *fio, const char *desc, char *buf)
191 /* set to empty string */
196 snprintf(buf, GMX_FIO_BUFLEN, " ; %s %s", fio->comment ? fio->comment : "", desc);
202 /* check the number of items given against the type */
203 void gmx_fio_check_nitem(int eio, int nitem, const char *file, int line)
205 if ((nitem != 1) && !((eio == eioNRVEC) || (eio == eioNUCHAR)))
208 "nitem (%d) may differ from 1 only for %s or %s, not for %s"
209 "(%s, %d)", nitem, eioNames[eioNUCHAR], eioNames[eioNRVEC],
210 eioNames[eio], file, line);
215 /* output a data type error. */
216 void gmx_fio_fe(t_fileio *fio, int eio, const char *desc,
217 const char *srcfile, int line)
220 gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d",
221 fio->bRead ? "read" : "write", desc, eio,
222 ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown",
227 /* set the reader/writer functions based on the file type */
228 static void gmx_fio_set_iotype(t_fileio *fio)
230 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
233 fio->iotp = &xdr_iotype;
235 gmx_fatal(FARGS, "Sorry, no XDR");
238 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
240 fio->iotp = &asc_iotype;
242 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
244 fio->iotp = &bin_iotype;
247 else if (in_ftpset(fio->iFTP, asize(ftpXML), ftpXML))
249 fio->iotp = &dummy_iotype;
254 fio->iotp = &dummy_iotype;
259 /* lock the mutex associated with this fio. This needs to be done for every
260 type of access to the fio's elements. */
261 void gmx_fio_lock(t_fileio *fio)
263 tMPI_Lock_lock(&(fio->mtx));
265 /* unlock the mutex associated with this fio. */
266 void gmx_fio_unlock(t_fileio *fio)
268 tMPI_Lock_unlock(&(fio->mtx));
271 /* make a dummy head element, assuming we locked everything. */
272 static void gmx_fio_make_dummy(void)
277 open_files->fp = NULL;
278 open_files->fn = NULL;
279 open_files->next = open_files;
280 open_files->prev = open_files;
281 tMPI_Lock_init(&(open_files->mtx));
291 /***********************************************************************
293 * FILE LIST OPERATIONS
295 ***********************************************************************/
298 /* insert a new t_fileio into the list */
299 static void gmx_fio_insert(t_fileio *fio)
302 /* first lock the big open_files mutex. */
303 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 /* now unlock the big open_files mutex. */
333 tMPI_Thread_mutex_unlock(&open_file_mutex);
336 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
338 NOTE: We also assume that the open_file_mutex has been locked */
339 static void gmx_fio_remove(t_fileio *fio)
343 /* lock prev, because we're changing it */
344 gmx_fio_lock(fio->prev);
346 /* now set the prev's pointer */
347 fio->prev->next = fio->next;
348 gmx_fio_unlock(fio->prev);
350 /* with the next ptr, we can simply lock while the original was locked */
351 gmx_fio_lock(fio->next);
352 fio->next->prev = fio->prev;
353 gmx_fio_unlock(fio->next);
355 /* and make sure we point nowhere in particular */
356 fio->next = fio->prev = fio;
360 /* get the first open file, or NULL if there is none.
361 Returns a locked fio. */
362 static t_fileio *gmx_fio_get_first(void)
365 /* first lock the big open_files mutex and the dummy's mutex */
367 /* first lock the big open_files mutex. */
368 tMPI_Thread_mutex_lock(&open_file_mutex);
369 gmx_fio_make_dummy();
371 gmx_fio_lock(open_files);
372 ret = open_files->next;
375 /* check whether there were any to begin with */
376 if (ret == open_files)
378 /* after this, the open_file pointer should never change */
383 gmx_fio_lock(open_files->next);
385 gmx_fio_unlock(open_files);
391 /* get the next open file, or NULL if there is none.
392 Unlocks the previous fio and locks the next one. */
393 static t_fileio *gmx_fio_get_next(t_fileio *fio)
398 /* check if that was the last one */
399 if (fio->next == open_files)
402 tMPI_Thread_mutex_unlock(&open_file_mutex);
413 /* Stop looping through the open_files. Unlocks the global lock. */
414 static void gmx_fio_stop_getting_next(t_fileio *fio)
417 tMPI_Thread_mutex_unlock(&open_file_mutex);
423 /*****************************************************************
427 *****************************************************************/
428 t_fileio *gmx_fio_open(const char *fn, const char *mode)
430 t_fileio *fio = NULL;
433 gmx_bool bRead, bReadWrite;
436 if (fn2ftp(fn) == efTPA)
438 strcpy(newmode, mode);
442 /* sanitize the mode string */
443 if (strncmp(mode, "r+", 2) == 0)
445 strcpy(newmode, "r+");
447 else if (mode[0] == 'r')
449 strcpy(newmode, "r");
451 else if (strncmp(mode, "w+", 2) == 0)
453 strcpy(newmode, "w+");
455 else if (mode[0] == 'w')
457 strcpy(newmode, "w");
459 else if (strncmp(mode, "a+", 2) == 0)
461 strcpy(newmode, "a+");
463 else if (mode[0] == 'a')
465 strcpy(newmode, "a");
469 gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'", mode);
473 /* Check if it should be opened as a binary file */
474 if (strncmp(ftp2ftype(fn2ftp(fn)), "ASCII", 5))
476 /* Not ascii, add b to file mode */
477 if ((strchr(newmode, 'b') == NULL) && (strchr(newmode, 'B') == NULL))
479 strcat(newmode, "b");
484 tMPI_Lock_init(&(fio->mtx));
485 bRead = (newmode[0] == 'r' && newmode[1] != '+');
486 bReadWrite = (newmode[1] == '+');
491 fio->iFTP = fn2ftp(fn);
492 fio->fn = strdup(fn);
495 /* If this file type is in the list of XDR files, open it like that */
496 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
498 /* First check whether we have to make a backup,
499 * only for writing, not for read or append.
501 if (newmode[0] == 'w')
504 /* only make backups for normal gromacs */
510 /* Check whether file exists */
516 if (fn2ftp(fn) == efTNG)
518 gmx_incons("gmx_fio_open may not be used to open TNG files");
521 fio->fp = gmx_ffopen(fn, newmode);
523 /* determine the XDR direction */
524 if (newmode[0] == 'w' || newmode[0] == 'a')
526 fio->xdrmode = XDR_ENCODE;
530 fio->xdrmode = XDR_DECODE;
534 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
538 /* If it is not, open it as a regular file */
539 fio->fp = gmx_ffopen(fn, newmode);
542 /* for appending seek to end of file to make sure ftell gives correct position
543 * important for checkpointing */
544 if (newmode[0] == 'a')
546 gmx_fseek(fio->fp, 0, SEEK_END);
551 /* Use stdin/stdout for I/O */
553 fio->fp = bRead ? stdin : stdout;
554 fio->fn = strdup("STDIO");
558 fio->bReadWrite = bReadWrite;
559 fio->bDouble = (sizeof(real) == sizeof(double));
563 /* set the reader/writer functions */
564 gmx_fio_set_iotype(fio);
566 /* and now insert this file into the list of open files. */
571 static int gmx_fio_close_locked(t_fileio *fio)
577 gmx_fatal(FARGS, "File %s closed twice!\n", fio->fn);
580 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
582 xdr_destroy(fio->xdr);
586 /* Don't close stdin and stdout! */
587 if (!fio->bStdio && fio->fp != NULL)
589 rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
597 int gmx_fio_close(t_fileio *fio)
601 /* first lock the big open_files mutex. */
602 /* We don't want two processes operating on the list at the same time */
603 tMPI_Thread_mutex_lock(&open_file_mutex);
605 if (fio->iFTP == efTNG)
607 gmx_incons("gmx_fio_close should not be called on a TNG file");
610 /* first remove it from the list */
612 rc = gmx_fio_close_locked(fio);
618 tMPI_Thread_mutex_unlock(&open_file_mutex);
623 /* close only fp but keep FIO entry. */
624 int gmx_fio_fp_close(t_fileio *fio)
628 if (!in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR) && !fio->bStdio)
630 rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
638 FILE * gmx_fio_fopen(const char *fn, const char *mode)
643 fio = gmx_fio_open(fn, mode);
651 int gmx_fio_fclose(FILE *fp)
654 t_fileio *found = NULL;
657 cur = gmx_fio_get_first();
662 rc = gmx_fio_close_locked(cur);
664 gmx_fio_stop_getting_next(cur);
669 cur = gmx_fio_get_next(cur);
675 /* internal variant of get_file_md5 that operates on a locked file */
676 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
677 unsigned char digest[])
679 /*1MB: large size important to catch almost identical files */
680 #define CPT_CHK_LEN 1048576
684 gmx_off_t seek_offset;
687 seek_offset = offset - CPT_CHK_LEN;
692 read_len = offset - seek_offset;
695 if (fio->fp && fio->bReadWrite)
697 ret = gmx_fseek(fio->fp, seek_offset, SEEK_SET);
700 gmx_fseek(fio->fp, 0, SEEK_END);
703 if (ret) /*either no fp, not readwrite, or fseek not successful */
708 snew(buf, CPT_CHK_LEN);
709 /* the read puts the file position back to offset */
710 if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
712 /* not fatal: md5sum check to prevent overwriting files
713 * works (less safe) without
717 fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
720 else if (feof(fio->fp))
723 * For long runs that checkpoint frequently but write e.g. logs
724 * infrequently we don't want to issue lots of warnings before we
725 * have written anything to the log.
729 fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
736 "\nTrying to get md5sum: Unknown reason for short read: %s\n",
740 gmx_fseek(fio->fp, 0, SEEK_END);
744 gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows
745 it gives problems otherwise*/
749 fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
754 gmx_md5_init(&state);
755 gmx_md5_append(&state, buf, read_len);
756 gmx_md5_finish(&state, digest);
765 * fio: file to compute md5 for
766 * offset: starting pointer of region to use for md5
767 * digest: return array of md5 sum
769 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
770 unsigned char digest[])
775 ret = gmx_fio_int_get_file_md5(fio, offset, digest);
781 /* The fio_mutex should ALWAYS be locked when this function is called */
782 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
786 /* Flush the file, so we are sure it is written */
787 if (gmx_fio_int_flush(fio))
792 "Cannot write file '%s'; maybe you are out of disk space?",
797 /* We cannot count on XDR being able to write 64-bit integers,
798 so separate into high/low 32-bit values.
799 In case the filesystem has 128-bit offsets we only care
800 about the first 64 bits - we'll have to fix
801 this when exabyte-size output files are common...
803 *offset = gmx_ftell(fio->fp);
808 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
811 int i, nfiles, rc, nalloc;
814 gmx_file_position_t * outputfiles;
820 /* pre-allocate 100 files */
822 snew(outputfiles, nalloc);
824 cur = gmx_fio_get_first();
827 /* Skip the checkpoint files themselves, since they could be open when
828 we call this routine... */
829 /* also skip debug files (shoud be the only iFTP==efNR) */
833 cur->iFTP != efCPT &&
837 /* This is an output file currently open for writing, add it */
838 if (nfiles == nalloc)
841 srenew(outputfiles, nalloc);
844 strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
846 /* Get the file position */
847 gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
849 outputfiles[nfiles].chksum_size
850 = gmx_fio_int_get_file_md5(cur,
851 outputfiles[nfiles].offset,
852 outputfiles[nfiles].chksum);
857 cur = gmx_fio_get_next(cur);
860 *p_outputfiles = outputfiles;
866 void gmx_fio_checktype(t_fileio *fio)
868 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
872 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
876 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
881 else if (in_ftpset(fio->iFTP, asize(ftpXML), ftpXML))
888 gmx_fatal(FARGS, "Can not read/write topologies to file type %s",
895 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
898 fio->bDouble = bDouble;
902 gmx_bool gmx_fio_getdebug(t_fileio *fio)
913 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
916 fio->bDebug = bDebug;
920 char *gmx_fio_getname(t_fileio *fio)
930 int gmx_fio_getftp(t_fileio* fio)
941 void gmx_fio_rewind(t_fileio* fio)
947 xdr_destroy(fio->xdr);
949 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
959 int gmx_fio_flush(t_fileio* fio)
964 ret = gmx_fio_int_flush(fio);
972 static int gmx_fio_int_fsync(t_fileio *fio)
980 rc = gmx_fsync(fio->fp);
982 else if (fio->xdr) /* this should normally not happen */
984 rc = gmx_fsync((FILE*) fio->xdr->x_private);
985 /* ^ is this actually OK? */
992 int gmx_fio_fsync(t_fileio *fio)
997 rc = gmx_fio_int_fsync(fio);
1005 t_fileio *gmx_fio_all_output_fsync(void)
1007 t_fileio *ret = NULL;
1010 cur = gmx_fio_get_first();
1013 /* skip debug files (shoud be the only iFTP==efNR) */
1019 /* if any of them fails, return failure code */
1020 int rc = gmx_fio_int_fsync(cur);
1021 if (rc != 0 && !ret)
1026 cur = gmx_fio_get_next(cur);
1029 /* in addition, we force these to be written out too, if they're being
1030 redirected. We don't check for errors because errors most likely mean
1031 that they're not redirected. */
1034 #if (defined(HAVE_FSYNC))
1035 /* again, fahcore defines HAVE_FSYNC and fsync() */
1036 fsync(STDOUT_FILENO);
1037 fsync(STDERR_FILENO);
1044 gmx_off_t gmx_fio_ftell(t_fileio* fio)
1051 ret = gmx_ftell(fio->fp);
1053 gmx_fio_unlock(fio);
1057 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
1064 rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
1071 gmx_fio_unlock(fio);
1075 FILE *gmx_fio_getfp(t_fileio *fio)
1084 gmx_fio_unlock(fio);
1088 XDR *gmx_fio_getxdr(t_fileio* fio)
1097 gmx_fio_unlock(fio);
1102 gmx_bool gmx_fio_getread(t_fileio* fio)
1108 gmx_fio_unlock(fio);
1113 int xtc_seek_frame(t_fileio *fio, int frame, int natoms)
1118 ret = xdr_xtc_seek_frame(frame, fio->fp, fio->xdr, natoms);
1119 gmx_fio_unlock(fio);
1124 int xtc_seek_time(t_fileio *fio, real time, int natoms, gmx_bool bSeekForwardOnly)
1129 ret = xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms, bSeekForwardOnly);
1130 gmx_fio_unlock(fio);