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] =
96 { "[header]", "[inputrec]", "[box]", "[topology]", "[coordinates]",
97 "[velocities]", "[forces]" };
99 const char *eioNames[eioNR] =
100 { "REAL", "INT", "GMX_STE_T", "UCHAR", "NUCHAR", "USHORT", "RVEC", "NRVEC",
105 /* Comment strings for TPA only */
106 const char *comment_str[eitemNR] = {
107 "; The header holds information on the number of atoms etc. and on whether\n"
108 "; certain items are present in the file or not.\n"
111 "; DO NOT EDIT THIS FILE BY HAND\n"
112 "; The GROMACS preprocessor performs a lot of checks on your input that\n"
113 "; you ignore when editing this. Your simulation may crash because of this\n",
114 "; The inputrec holds the parameters for MD such as the number of steps,\n"
115 "; the timestep and the cut-offs.\n",
116 "; The simulation box in nm.\n",
117 "; The topology section describes the topology of the molecules\n"
118 "; i.e. bonds, angles and dihedrals etc. and also holds the force field\n"
120 "; The atomic coordinates in nm\n",
121 "; The atomic velocities in nm/ps\n",
122 "; The forces on the atoms in nm/ps^2\n" };
127 /******************************************************************
129 * Internal functions:
131 ******************************************************************/
133 static int gmx_fio_int_flush(t_fileio* fio)
139 rc = fflush(fio->fp);
143 rc = fflush((FILE *) fio->xdr->x_private);
149 /* returns TRUE if the file type ftp is in the set set */
150 static gmx_bool in_ftpset(int ftp, int nset, const int set[])
156 for (i = 0; (i < nset); i++)
165 extern void gmx_fio_set_comment(t_fileio *fio, const char *comment)
167 fio->comment=comment;
170 extern void gmx_fio_unset_comment(t_fileio *fio)
176 const char *gmx_fio_dbgstr(t_fileio *fio, const char *desc, char *buf)
180 /* set to empty string */
185 snprintf(buf, GMX_FIO_BUFLEN, " ; %s %s", fio->comment ? fio->comment : "", desc);
191 /* check the number of items given against the type */
192 void gmx_fio_check_nitem(t_fileio *fio, int eio, int nitem, const char *file,
195 if ((nitem != 1) && !((eio == eioNRVEC) || (eio == eioNUCHAR)))
197 "nitem (%d) may differ from 1 only for %s or %s, not for %s"
198 "(%s, %d)",nitem,eioNames[eioNUCHAR],eioNames[eioNRVEC],
199 eioNames[eio],file,line);
203 /* output a data type error. */
204 void gmx_fio_fe(t_fileio *fio, int eio, const char *desc,
205 const char *srcfile, int line)
208 gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d",
209 fio->bRead ? "read" : "write",desc,eio,
210 ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown",
215 /* set the reader/writer functions based on the file type */
216 static void gmx_fio_set_iotype(t_fileio *fio)
218 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
221 fio->iotp=&xdr_iotype;
223 gmx_fatal(FARGS,"Sorry, no XDR");
226 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
228 fio->iotp=&asc_iotype;
230 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
232 fio->iotp=&bin_iotype;
235 fio->iotp=&dummy_iotype;
239 /* lock the mutex associated with this fio. This needs to be done for every
240 type of access to the fio's elements. */
241 void gmx_fio_lock(t_fileio *fio)
243 #ifdef GMX_THREAD_MPI
244 tMPI_Lock_lock(&(fio->mtx));
247 /* unlock the mutex associated with this fio. */
248 void gmx_fio_unlock(t_fileio *fio)
250 #ifdef GMX_THREAD_MPI
251 tMPI_Lock_unlock(&(fio->mtx));
255 /* make a dummy head element, assuming we locked everything. */
256 static void gmx_fio_make_dummy(void)
263 open_files->next=open_files;
264 open_files->prev=open_files;
265 #ifdef GMX_THREAD_MPI
266 tMPI_Lock_init(&(open_files->mtx));
277 /***********************************************************************
279 * FILE LIST OPERATIONS
281 ***********************************************************************/
284 /* insert a new t_fileio into the list */
285 static void gmx_fio_insert(t_fileio *fio)
288 #ifdef GMX_THREAD_MPI
289 /* first lock the big open_files mutex. */
290 tMPI_Thread_mutex_lock(&open_file_mutex);
292 /* now check whether the dummy element has been allocated,
293 and allocate it if it hasn't */
294 gmx_fio_make_dummy();
296 /* and lock the fio we got and the list's head **/
298 gmx_fio_lock(open_files);
299 prev=open_files->prev;
300 /* lock the element after the current one */
301 if (prev != open_files)
306 /* now do the actual insertion: */
307 fio->next=open_files;
308 open_files->prev=fio;
312 /* now unlock all our locks */
313 if (prev != open_files)
315 gmx_fio_unlock(prev);
317 gmx_fio_unlock(open_files);
320 #ifdef GMX_THREAD_MPI
321 /* now unlock the big open_files mutex. */
322 tMPI_Thread_mutex_unlock(&open_file_mutex);
326 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
328 NOTE: We also assume that the open_file_mutex has been locked */
329 static void gmx_fio_remove(t_fileio *fio)
333 /* lock prev, because we're changing it */
334 gmx_fio_lock(fio->prev);
336 /* now set the prev's pointer */
337 fio->prev->next=fio->next;
338 gmx_fio_unlock(fio->prev);
340 /* with the next ptr, we can simply lock while the original was locked */
341 gmx_fio_lock(fio->next);
342 fio->next->prev=fio->prev;
343 gmx_fio_unlock(fio->next);
345 /* and make sure we point nowhere in particular */
346 fio->next=fio->prev=fio;
350 /* get the first open file, or NULL if there is none.
351 Returns a locked fio. */
352 static t_fileio *gmx_fio_get_first(void)
355 /* first lock the big open_files mutex and the dummy's mutex */
357 #ifdef GMX_THREAD_MPI
358 /* first lock the big open_files mutex. */
359 tMPI_Thread_mutex_lock(&open_file_mutex);
361 gmx_fio_make_dummy();
363 gmx_fio_lock(open_files);
364 ret=open_files->next;
367 /* check whether there were any to begin with */
370 /* after this, the open_file pointer should never change */
375 gmx_fio_lock(open_files->next);
377 gmx_fio_unlock(open_files);
383 /* get the next open file, or NULL if there is none.
384 Unlocks the previous fio and locks the next one. */
385 static t_fileio *gmx_fio_get_next(t_fileio *fio)
390 /* check if that was the last one */
391 if (fio->next==open_files)
394 #ifdef GMX_THREAD_MPI
395 tMPI_Thread_mutex_unlock(&open_file_mutex);
407 /* Stop looping through the open_files. Unlocks the global lock. */
408 static void gmx_fio_stop_getting_next(t_fileio *fio)
411 #ifdef GMX_THREAD_MPI
412 tMPI_Thread_mutex_unlock(&open_file_mutex);
419 /*****************************************************************
423 *****************************************************************/
424 t_fileio *gmx_fio_open(const char *fn, const char *mode)
426 t_fileio *fio = NULL;
429 gmx_bool bRead, bReadWrite;
432 if (fn2ftp(fn) == efTPA)
434 strcpy(newmode, mode);
438 /* sanitize the mode string */
439 if (strncmp(mode, "r+", 2) == 0)
441 strcpy(newmode, "r+");
443 else if (mode[0] == 'r')
445 strcpy(newmode, "r");
447 else if (strncmp(mode, "w+", 2) == 0)
449 strcpy(newmode, "w+");
451 else if (mode[0] == 'w')
453 strcpy(newmode, "w");
455 else if (strncmp(mode, "a+", 2) == 0)
457 strcpy(newmode, "a+");
459 else if (mode[0] == 'a')
461 strcpy(newmode, "a");
465 gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'",mode);
469 /* Check if it should be opened as a binary file */
470 if (strncmp(ftp2ftype(fn2ftp(fn)),"ASCII",5))
472 /* Not ascii, add b to file mode */
473 if ((strchr(newmode,'b')==NULL) && (strchr(newmode,'B')==NULL))
480 #ifdef GMX_THREAD_MPI
481 tMPI_Lock_init(&(fio->mtx));
483 bRead = (newmode[0]=='r' && newmode[1]!='+');
484 bReadWrite = (newmode[1]=='+');
489 fio->iFTP = fn2ftp(fn);
490 fio->fn = 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.
502 /* only make backups for normal gromacs */
508 /* Check whether file exists */
515 fio->fp = ffopen(fn,newmode);
517 /* determine the XDR direction */
518 if (newmode[0] == 'w' || newmode[0]=='a')
520 fio->xdrmode=XDR_ENCODE;
524 fio->xdrmode=XDR_DECODE;
528 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
532 /* If it is not, open it as a regular file */
533 fio->fp = ffopen(fn,newmode);
536 /* for appending seek to end of file to make sure ftell gives correct position
537 * important for checkpointing */
540 gmx_fseek(fio->fp, 0, SEEK_END);
545 /* Use stdin/stdout for I/O */
547 fio->fp = bRead ? stdin : stdout;
548 fio->fn = strdup("STDIO");
552 fio->bReadWrite = bReadWrite;
553 fio->bDouble= (sizeof(real) == sizeof(double));
556 fio->bLargerThan_off_t = FALSE;
558 /* set the reader/writer functions */
559 gmx_fio_set_iotype(fio);
561 /* and now insert this file into the list of open files. */
566 static int gmx_fio_close_locked(t_fileio *fio)
572 gmx_fatal(FARGS,"File %s closed twice!\n", fio->fn);
575 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
577 xdr_destroy(fio->xdr);
581 /* Don't close stdin and stdout! */
582 if (!fio->bStdio && fio->fp!=NULL)
583 rc = ffclose(fio->fp); /* fclose returns 0 if happy */
590 int gmx_fio_close(t_fileio *fio)
594 #ifdef GMX_THREAD_MPI
595 /* first lock the big open_files mutex. */
596 /* We don't want two processes operating on the list at the same time */
597 tMPI_Thread_mutex_lock(&open_file_mutex);
601 /* first remove it from the list */
603 rc=gmx_fio_close_locked(fio);
608 #ifdef GMX_THREAD_MPI
609 tMPI_Thread_mutex_unlock(&open_file_mutex);
615 /* close only fp but keep FIO entry. */
616 int gmx_fio_fp_close(t_fileio *fio)
620 if (!in_ftpset(fio->iFTP,asize(ftpXDR),ftpXDR) && !fio->bStdio)
622 rc = ffclose(fio->fp); /* fclose returns 0 if happy */
630 FILE * gmx_fio_fopen(const char *fn, const char *mode)
635 fio = gmx_fio_open(fn, mode);
643 int gmx_fio_fclose(FILE *fp)
646 t_fileio *found=NULL;
649 cur=gmx_fio_get_first();
654 rc=gmx_fio_close_locked(cur);
656 gmx_fio_stop_getting_next(cur);
659 cur=gmx_fio_get_next(cur);
665 /* internal variant of get_file_md5 that operates on a locked file */
666 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
667 unsigned char digest[])
669 /*1MB: large size important to catch almost identical files */
670 #define CPT_CHK_LEN 1048576
672 unsigned char buf[CPT_CHK_LEN];
674 gmx_off_t seek_offset;
677 seek_offset = offset - CPT_CHK_LEN;
682 read_len = offset - seek_offset;
685 if (fio->fp && fio->bReadWrite)
687 ret=gmx_fseek(fio->fp, seek_offset, SEEK_SET);
690 gmx_fseek(fio->fp, 0, SEEK_END);
693 if (ret) /*either no fp, not readwrite, or fseek not successful */
698 /* the read puts the file position back to offset */
699 if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
701 /* not fatal: md5sum check to prevent overwriting files
702 * works (less safe) without
706 fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
709 else if (feof(fio->fp))
712 * For long runs that checkpoint frequently but write e.g. logs
713 * infrequently we don't want to issue lots of warnings before we
714 * have written anything to the log.
718 fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
725 "\nTrying to get md5sum: Unknown reason for short read: %s\n",
729 gmx_fseek(fio->fp, 0, SEEK_END);
733 gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows
734 it gives problems otherwise*/
738 fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
744 md5_append(&state, buf, read_len);
745 md5_finish(&state, digest);
756 * fio: file to compute md5 for
757 * offset: starting pointer of region to use for md5
758 * digest: return array of md5 sum
760 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
761 unsigned char digest[])
766 ret=gmx_fio_int_get_file_md5(fio, offset, digest);
772 /* The fio_mutex should ALWAYS be locked when this function is called */
773 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
777 /* Flush the file, so we are sure it is written */
778 if (gmx_fio_int_flush(fio))
783 "Cannot write file '%s'; maybe you are out of disk space?",
788 /* We cannot count on XDR being able to write 64-bit integers,
789 so separate into high/low 32-bit values.
790 In case the filesystem has 128-bit offsets we only care
791 about the first 64 bits - we'll have to fix
792 this when exabyte-size output files are common...
794 *offset=gmx_ftell(fio->fp);
799 int gmx_fio_check_file_position(t_fileio *fio)
801 /* If gmx_off_t is 4 bytes we can not store file offset > 2 GB.
802 * If we do not have ftello, we will play it safe.
804 #if (SIZEOF_GMX_OFF_T == 4 || !defined HAVE_FSEEKO)
808 gmx_fio_int_get_file_position(fio,&offset);
809 /* We have a 4 byte offset,
810 * make sure that we will detect out of range for all possible cases.
812 if (offset < 0 || offset > 2147483647)
814 fio->bLargerThan_off_t = TRUE;
822 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
825 int i, nfiles, rc, nalloc;
828 gmx_file_position_t * outputfiles;
834 /* pre-allocate 100 files */
836 snew(outputfiles,nalloc);
838 cur=gmx_fio_get_first();
841 /* Skip the checkpoint files themselves, since they could be open when
842 we call this routine... */
843 /* also skip debug files (shoud be the only iFTP==efNR) */
847 cur->iFTP != efCPT &&
851 /* This is an output file currently open for writing, add it */
852 if (nfiles == nalloc)
855 srenew(outputfiles,nalloc);
858 strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
860 /* Get the file position */
861 if (cur->bLargerThan_off_t)
863 /* -1 signals out of range */
864 outputfiles[nfiles].offset = -1;
865 outputfiles[nfiles].chksum_size = -1;
869 gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
871 outputfiles[nfiles].chksum_size
872 = gmx_fio_int_get_file_md5(cur,
873 outputfiles[nfiles].offset,
874 outputfiles[nfiles].chksum);
881 cur=gmx_fio_get_next(cur);
884 *p_outputfiles = outputfiles;
890 void gmx_fio_checktype(t_fileio *fio)
892 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
896 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
900 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
905 gmx_fatal(FARGS, "Can not read/write topologies to file type %s",
911 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
914 fio->bDouble = bDouble;
918 gmx_bool gmx_fio_getdebug(t_fileio *fio)
929 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
932 fio->bDebug = bDebug;
936 char *gmx_fio_getname(t_fileio *fio)
946 int gmx_fio_getftp(t_fileio* fio)
957 void gmx_fio_rewind(t_fileio* fio)
963 xdr_destroy(fio->xdr);
965 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
975 int gmx_fio_flush(t_fileio* fio)
980 ret=gmx_fio_int_flush(fio);
988 static int gmx_fio_int_fsync(t_fileio *fio)
996 rc=gmx_fsync(fio->fp);
998 else if (fio->xdr) /* this should normally not happen */
1000 rc=gmx_fsync((FILE*) fio->xdr->x_private);
1001 /* ^ is this actually OK? */
1008 int gmx_fio_fsync(t_fileio *fio)
1013 rc=gmx_fio_int_fsync(fio);
1014 gmx_fio_unlock(fio);
1021 t_fileio *gmx_fio_all_output_fsync(void)
1026 cur=gmx_fio_get_first();
1029 /* skip debug files (shoud be the only iFTP==efNR) */
1035 /* if any of them fails, return failure code */
1036 int rc=gmx_fio_int_fsync(cur);
1037 if (rc != 0 && !ret)
1042 cur=gmx_fio_get_next(cur);
1045 /* in addition, we force these to be written out too, if they're being
1046 redirected. We don't check for errors because errors most likely mean
1047 that they're not redirected. */
1050 #if (defined(HAVE_FSYNC))
1051 /* again, fahcore defines HAVE_FSYNC and fsync() */
1052 fsync(STDOUT_FILENO);
1053 fsync(STDERR_FILENO);
1060 gmx_off_t gmx_fio_ftell(t_fileio* fio)
1066 ret = gmx_ftell(fio->fp);
1067 gmx_fio_unlock(fio);
1071 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
1078 rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
1085 gmx_fio_unlock(fio);
1089 FILE *gmx_fio_getfp(t_fileio *fio)
1096 gmx_fio_unlock(fio);
1100 XDR *gmx_fio_getxdr(t_fileio* fio)
1107 gmx_fio_unlock(fio);
1112 gmx_bool gmx_fio_getread(t_fileio* fio)
1118 gmx_fio_unlock(fio);
1123 int xtc_seek_frame(t_fileio *fio, int frame, int natoms)
1128 ret=xdr_xtc_seek_frame(frame, fio->fp, fio->xdr, natoms);
1129 gmx_fio_unlock(fio);
1134 int xtc_seek_time(t_fileio *fio, real time, int natoms,gmx_bool bSeekForwardOnly)
1139 ret=xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms, bSeekForwardOnly);
1140 gmx_fio_unlock(fio);