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,2015, 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.
54 #include "thread_mpi/threads.h"
56 #include "gromacs/fileio/filenm.h"
57 #include "gromacs/fileio/md5.h"
58 #include "gromacs/legacyheaders/macros.h"
59 #include "gromacs/utility/fatalerror.h"
60 #include "gromacs/utility/futil.h"
61 #include "gromacs/utility/smalloc.h"
63 #include "gmxfio-impl.h"
65 /* This is the new improved and thread safe version of gmxfio. */
69 /* the list of open files is a linked list, with a dummy element at its head;
70 it is initialized when the first file is opened. */
71 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;
86 /* These simple lists define the I/O type for these files */
87 static const int ftpXDR[] =
88 { efTPR, efTRR, efEDR, efXTC, efTNG, efMTX, efCPT };
90 const char *eioNames[eioNR] =
92 "REAL", "INT", "GMX_STE_T", "UCHAR", "NUCHAR", "USHORT", "RVEC", "NRVEC",
97 static gmx_bool do_dummyread(t_fileio *fio, void *item, int nitem, int eio,
98 const char *desc, const char *srcfile, int line);
99 static gmx_bool do_dummywrite(t_fileio *fio, const void *item, int nitem, int eio,
100 const char *desc, const char *srcfile, int line);
102 const t_iotype dummy_iotype = {do_dummyread, do_dummywrite};
104 static gmx_bool do_dummyread(
105 t_fileio gmx_unused *fio, void gmx_unused *item, int gmx_unused nitem, int gmx_unused eio,
106 const char gmx_unused *desc, const char gmx_unused *srcfile, int gmx_unused line)
108 gmx_fatal(FARGS, "File type not set!");
112 static gmx_bool do_dummywrite(
113 t_fileio gmx_unused *fio, const void gmx_unused *item, int gmx_unused nitem, int gmx_unused eio,
114 const char gmx_unused *desc, const char gmx_unused *srcfile, int gmx_unused line)
116 gmx_fatal(FARGS, "File type not set!");
120 /******************************************************************
122 * Internal functions:
124 ******************************************************************/
126 static int gmx_fio_int_flush(t_fileio* fio)
132 rc = fflush(fio->fp);
136 rc = fflush((FILE *) fio->xdr->x_private);
142 /* returns TRUE if the file type ftp is in the set set */
143 static gmx_bool in_ftpset(int ftp, int nset, const int set[])
149 for (i = 0; (i < nset); i++)
161 /* check the number of items given against the type */
162 void gmx_fio_check_nitem(int eio, int nitem, const char *file, int line)
164 if ((nitem != 1) && !((eio == eioNRVEC) || (eio == eioNUCHAR)))
167 "nitem (%d) may differ from 1 only for %s or %s, not for %s"
168 "(%s, %d)", nitem, eioNames[eioNUCHAR], eioNames[eioNRVEC],
169 eioNames[eio], file, line);
174 /* output a data type error. */
175 void gmx_fio_fe(t_fileio *fio, int eio, const char *desc,
176 const char *srcfile, int line)
179 gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d",
180 fio->bRead ? "read" : "write", desc, eio,
181 ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown",
186 /* set the reader/writer functions based on the file type */
187 static void gmx_fio_set_iotype(t_fileio *fio)
189 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
191 fio->iotp = &xdr_iotype;
195 fio->iotp = &dummy_iotype;
200 /* lock the mutex associated with this fio. This needs to be done for every
201 type of access to the fio's elements. */
202 void gmx_fio_lock(t_fileio *fio)
204 tMPI_Lock_lock(&(fio->mtx));
206 /* unlock the mutex associated with this fio. */
207 void gmx_fio_unlock(t_fileio *fio)
209 tMPI_Lock_unlock(&(fio->mtx));
212 /* make a dummy head element, assuming we locked everything. */
213 static void gmx_fio_make_dummy(void)
218 open_files->fp = NULL;
219 open_files->fn = NULL;
220 open_files->next = open_files;
221 open_files->prev = open_files;
222 tMPI_Lock_init(&(open_files->mtx));
232 /***********************************************************************
234 * FILE LIST OPERATIONS
236 ***********************************************************************/
239 /* insert a new t_fileio into the list */
240 static void gmx_fio_insert(t_fileio *fio)
243 /* first lock the big open_files mutex. */
244 tMPI_Thread_mutex_lock(&open_file_mutex);
245 /* now check whether the dummy element has been allocated,
246 and allocate it if it hasn't */
247 gmx_fio_make_dummy();
249 /* and lock the fio we got and the list's head **/
251 gmx_fio_lock(open_files);
252 prev = open_files->prev;
253 /* lock the element after the current one */
254 if (prev != open_files)
259 /* now do the actual insertion: */
260 fio->next = open_files;
261 open_files->prev = fio;
265 /* now unlock all our locks */
266 if (prev != open_files)
268 gmx_fio_unlock(prev);
270 gmx_fio_unlock(open_files);
273 /* now unlock the big open_files mutex. */
274 tMPI_Thread_mutex_unlock(&open_file_mutex);
277 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
279 NOTE: We also assume that the open_file_mutex has been locked */
280 static void gmx_fio_remove(t_fileio *fio)
284 /* lock prev, because we're changing it */
285 gmx_fio_lock(fio->prev);
287 /* now set the prev's pointer */
288 fio->prev->next = fio->next;
289 gmx_fio_unlock(fio->prev);
291 /* with the next ptr, we can simply lock while the original was locked */
292 gmx_fio_lock(fio->next);
293 fio->next->prev = fio->prev;
294 gmx_fio_unlock(fio->next);
296 /* and make sure we point nowhere in particular */
297 fio->next = fio->prev = fio;
301 /* get the first open file, or NULL if there is none.
302 Returns a locked fio. */
303 static t_fileio *gmx_fio_get_first(void)
306 /* first lock the big open_files mutex and the dummy's mutex */
308 /* first lock the big open_files mutex. */
309 tMPI_Thread_mutex_lock(&open_file_mutex);
310 gmx_fio_make_dummy();
312 gmx_fio_lock(open_files);
313 ret = open_files->next;
316 /* check whether there were any to begin with */
317 if (ret == open_files)
319 /* after this, the open_file pointer should never change */
324 gmx_fio_lock(open_files->next);
326 gmx_fio_unlock(open_files);
332 /* get the next open file, or NULL if there is none.
333 Unlocks the previous fio and locks the next one. */
334 static t_fileio *gmx_fio_get_next(t_fileio *fio)
339 /* check if that was the last one */
340 if (fio->next == open_files)
343 tMPI_Thread_mutex_unlock(&open_file_mutex);
354 /* Stop looping through the open_files. Unlocks the global lock. */
355 static void gmx_fio_stop_getting_next(t_fileio *fio)
358 tMPI_Thread_mutex_unlock(&open_file_mutex);
364 /*****************************************************************
368 *****************************************************************/
369 t_fileio *gmx_fio_open(const char *fn, const char *mode)
371 t_fileio *fio = NULL;
374 gmx_bool bRead, bReadWrite;
377 /* sanitize the mode string */
378 if (strncmp(mode, "r+", 2) == 0)
380 strcpy(newmode, "r+");
382 else if (mode[0] == 'r')
384 strcpy(newmode, "r");
386 else if (strncmp(mode, "w+", 2) == 0)
388 strcpy(newmode, "w+");
390 else if (mode[0] == 'w')
392 strcpy(newmode, "w");
394 else if (strncmp(mode, "a+", 2) == 0)
396 strcpy(newmode, "a+");
398 else if (mode[0] == 'a')
400 strcpy(newmode, "a");
404 gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'", mode);
407 /* Check if it should be opened as a binary file */
408 if (strncmp(ftp2ftype(fn2ftp(fn)), "ASCII", 5))
410 /* Not ascii, add b to file mode */
411 if ((strchr(newmode, 'b') == NULL) && (strchr(newmode, 'B') == NULL))
413 strcat(newmode, "b");
418 tMPI_Lock_init(&(fio->mtx));
419 bRead = (newmode[0] == 'r' && newmode[1] != '+');
420 bReadWrite = (newmode[1] == '+');
425 if (fn2ftp(fn) == efTNG)
427 gmx_incons("gmx_fio_open may not be used to open TNG files");
429 fio->iFTP = fn2ftp(fn);
430 fio->fn = gmx_strdup(fn);
432 /* If this file type is in the list of XDR files, open it like that */
433 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
435 /* First check whether we have to make a backup,
436 * only for writing, not for read or append.
438 if (newmode[0] == 'w')
441 /* only make backups for normal gromacs */
447 /* Check whether file exists */
454 fio->fp = gmx_ffopen(fn, newmode);
456 /* determine the XDR direction */
457 if (newmode[0] == 'w' || newmode[0] == 'a')
459 fio->xdrmode = XDR_ENCODE;
463 fio->xdrmode = XDR_DECODE;
467 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
471 /* If it is not, open it as a regular file */
472 fio->fp = gmx_ffopen(fn, newmode);
475 /* for appending seek to end of file to make sure ftell gives correct position
476 * important for checkpointing */
477 if (newmode[0] == 'a')
479 gmx_fseek(fio->fp, 0, SEEK_END);
483 fio->bReadWrite = bReadWrite;
484 fio->bDouble = (sizeof(real) == sizeof(double));
488 /* set the reader/writer functions */
489 gmx_fio_set_iotype(fio);
491 /* and now insert this file into the list of open files. */
496 static int gmx_fio_close_locked(t_fileio *fio)
502 gmx_fatal(FARGS, "File %s closed twice!\n", fio->fn);
505 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
507 xdr_destroy(fio->xdr);
513 rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
521 int gmx_fio_close(t_fileio *fio)
525 /* first lock the big open_files mutex. */
526 /* We don't want two processes operating on the list at the same time */
527 tMPI_Thread_mutex_lock(&open_file_mutex);
529 if (fio->iFTP == efTNG)
531 gmx_incons("gmx_fio_close should not be called on a TNG file");
534 /* first remove it from the list */
536 rc = gmx_fio_close_locked(fio);
542 tMPI_Thread_mutex_unlock(&open_file_mutex);
547 /* close only fp but keep FIO entry. */
548 int gmx_fio_fp_close(t_fileio *fio)
552 if (!in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
554 rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
562 FILE * gmx_fio_fopen(const char *fn, const char *mode)
567 fio = gmx_fio_open(fn, mode);
575 int gmx_fio_fclose(FILE *fp)
578 t_fileio *found = NULL;
581 cur = gmx_fio_get_first();
586 rc = gmx_fio_close_locked(cur);
588 gmx_fio_stop_getting_next(cur);
593 cur = gmx_fio_get_next(cur);
599 /* internal variant of get_file_md5 that operates on a locked file */
600 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
601 unsigned char digest[])
603 /*1MB: large size important to catch almost identical files */
604 #define CPT_CHK_LEN 1048576
608 gmx_off_t seek_offset;
611 seek_offset = offset - CPT_CHK_LEN;
616 read_len = offset - seek_offset;
619 if (fio->fp && fio->bReadWrite)
621 ret = gmx_fseek(fio->fp, seek_offset, SEEK_SET);
624 gmx_fseek(fio->fp, 0, SEEK_END);
627 if (ret) /*either no fp, not readwrite, or fseek not successful */
632 snew(buf, CPT_CHK_LEN);
633 /* the read puts the file position back to offset */
634 if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
636 /* not fatal: md5sum check to prevent overwriting files
637 * works (less safe) without
641 fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
644 else if (feof(fio->fp))
647 * For long runs that checkpoint frequently but write e.g. logs
648 * infrequently we don't want to issue lots of warnings before we
649 * have written anything to the log.
653 fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
660 "\nTrying to get md5sum: Unknown reason for short read: %s\n",
664 gmx_fseek(fio->fp, 0, SEEK_END);
668 gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows
669 it gives problems otherwise*/
673 fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
678 gmx_md5_init(&state);
679 gmx_md5_append(&state, buf, read_len);
680 gmx_md5_finish(&state, digest);
689 * fio: file to compute md5 for
690 * offset: starting pointer of region to use for md5
691 * digest: return array of md5 sum
693 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
694 unsigned char digest[])
699 ret = gmx_fio_int_get_file_md5(fio, offset, digest);
705 /* The fio_mutex should ALWAYS be locked when this function is called */
706 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
710 /* Flush the file, so we are sure it is written */
711 if (gmx_fio_int_flush(fio))
716 "Cannot write file '%s'; maybe you are out of disk space?",
721 /* We cannot count on XDR being able to write 64-bit integers,
722 so separate into high/low 32-bit values.
723 In case the filesystem has 128-bit offsets we only care
724 about the first 64 bits - we'll have to fix
725 this when exabyte-size output files are common...
727 *offset = gmx_ftell(fio->fp);
732 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
735 int i, nfiles, rc, nalloc;
738 gmx_file_position_t * outputfiles;
744 /* pre-allocate 100 files */
746 snew(outputfiles, nalloc);
748 cur = gmx_fio_get_first();
751 /* Skip the checkpoint files themselves, since they could be open when
752 we call this routine... */
753 if (cur->bOpen && !cur->bRead && cur->iFTP != efCPT)
756 /* This is an output file currently open for writing, add it */
757 if (nfiles == nalloc)
760 srenew(outputfiles, nalloc);
763 strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
765 /* Get the file position */
766 gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
768 outputfiles[nfiles].chksum_size
769 = gmx_fio_int_get_file_md5(cur,
770 outputfiles[nfiles].offset,
771 outputfiles[nfiles].chksum);
776 cur = gmx_fio_get_next(cur);
779 *p_outputfiles = outputfiles;
785 void gmx_fio_checktype(t_fileio *fio)
787 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
793 gmx_fatal(FARGS, "Can not read/write topologies to file type %s",
800 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
803 fio->bDouble = bDouble;
807 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
810 fio->bDebug = bDebug;
814 char *gmx_fio_getname(t_fileio *fio)
824 int gmx_fio_getftp(t_fileio* fio)
835 void gmx_fio_rewind(t_fileio* fio)
841 xdr_destroy(fio->xdr);
843 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
853 int gmx_fio_flush(t_fileio* fio)
858 ret = gmx_fio_int_flush(fio);
866 static int gmx_fio_int_fsync(t_fileio *fio)
874 rc = gmx_fsync(fio->fp);
876 else if (fio->xdr) /* this should normally not happen */
878 rc = gmx_fsync((FILE*) fio->xdr->x_private);
879 /* ^ is this actually OK? */
886 int gmx_fio_fsync(t_fileio *fio)
891 rc = gmx_fio_int_fsync(fio);
899 t_fileio *gmx_fio_all_output_fsync(void)
901 t_fileio *ret = NULL;
904 cur = gmx_fio_get_first();
907 if (cur->bOpen && !cur->bRead)
909 /* if any of them fails, return failure code */
910 int rc = gmx_fio_int_fsync(cur);
916 cur = gmx_fio_get_next(cur);
919 /* in addition, we force these to be written out too, if they're being
920 redirected. We don't check for errors because errors most likely mean
921 that they're not redirected. */
924 #if (defined(HAVE_FSYNC))
925 /* again, fahcore defines HAVE_FSYNC and fsync() */
926 fsync(STDOUT_FILENO);
927 fsync(STDERR_FILENO);
934 gmx_off_t gmx_fio_ftell(t_fileio* fio)
941 ret = gmx_ftell(fio->fp);
947 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
954 rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
965 FILE *gmx_fio_getfp(t_fileio *fio)
978 XDR *gmx_fio_getxdr(t_fileio* fio)
992 gmx_bool gmx_fio_getread(t_fileio* fio)
1003 int xtc_seek_time(t_fileio *fio, real time, int natoms, gmx_bool bSeekForwardOnly)
1008 ret = xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms, bSeekForwardOnly);
1009 gmx_fio_unlock(fio);