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 "gromacs/utility/fatalerror.h"
54 #include "gromacs/legacyheaders/macros.h"
55 #include "gromacs/utility/smalloc.h"
56 #include "gromacs/utility/futil.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 { efGRO, efPDB, efG96 };
90 static const int ftpBIN[] =
93 static const int ftpXML[] =
97 const char *eioNames[eioNR] =
99 "REAL", "INT", "GMX_STE_T", "UCHAR", "NUCHAR", "USHORT", "RVEC", "NRVEC",
103 /******************************************************************
105 * Internal functions:
107 ******************************************************************/
109 static int gmx_fio_int_flush(t_fileio* fio)
115 rc = fflush(fio->fp);
119 rc = fflush((FILE *) fio->xdr->x_private);
125 /* returns TRUE if the file type ftp is in the set set */
126 static gmx_bool in_ftpset(int ftp, int nset, const int set[])
132 for (i = 0; (i < nset); i++)
145 extern void gmx_fio_set_comment(t_fileio *fio, const char *comment)
147 fio->comment = comment;
150 extern void gmx_fio_unset_comment(t_fileio *fio)
156 const char *gmx_fio_dbgstr(t_fileio *fio, const char *desc, char *buf)
160 /* set to empty string */
165 snprintf(buf, GMX_FIO_BUFLEN, " ; %s %s", fio->comment ? fio->comment : "", desc);
171 /* check the number of items given against the type */
172 void gmx_fio_check_nitem(int eio, int nitem, const char *file, int line)
174 if ((nitem != 1) && !((eio == eioNRVEC) || (eio == eioNUCHAR)))
177 "nitem (%d) may differ from 1 only for %s or %s, not for %s"
178 "(%s, %d)", nitem, eioNames[eioNUCHAR], eioNames[eioNRVEC],
179 eioNames[eio], file, line);
184 /* output a data type error. */
185 void gmx_fio_fe(t_fileio *fio, int eio, const char *desc,
186 const char *srcfile, int line)
189 gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d",
190 fio->bRead ? "read" : "write", desc, eio,
191 ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown",
196 /* set the reader/writer functions based on the file type */
197 static void gmx_fio_set_iotype(t_fileio *fio)
199 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
202 fio->iotp = &xdr_iotype;
204 gmx_fatal(FARGS, "Sorry, no XDR");
207 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
209 fio->iotp = &asc_iotype;
211 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
213 fio->iotp = &bin_iotype;
216 else if (in_ftpset(fio->iFTP, asize(ftpXML), ftpXML))
218 fio->iotp = &dummy_iotype;
223 fio->iotp = &dummy_iotype;
228 /* lock the mutex associated with this fio. This needs to be done for every
229 type of access to the fio's elements. */
230 void gmx_fio_lock(t_fileio *fio)
232 tMPI_Lock_lock(&(fio->mtx));
234 /* unlock the mutex associated with this fio. */
235 void gmx_fio_unlock(t_fileio *fio)
237 tMPI_Lock_unlock(&(fio->mtx));
240 /* make a dummy head element, assuming we locked everything. */
241 static void gmx_fio_make_dummy(void)
246 open_files->fp = NULL;
247 open_files->fn = NULL;
248 open_files->next = open_files;
249 open_files->prev = open_files;
250 tMPI_Lock_init(&(open_files->mtx));
260 /***********************************************************************
262 * FILE LIST OPERATIONS
264 ***********************************************************************/
267 /* insert a new t_fileio into the list */
268 static void gmx_fio_insert(t_fileio *fio)
271 /* first lock the big open_files mutex. */
272 tMPI_Thread_mutex_lock(&open_file_mutex);
273 /* now check whether the dummy element has been allocated,
274 and allocate it if it hasn't */
275 gmx_fio_make_dummy();
277 /* and lock the fio we got and the list's head **/
279 gmx_fio_lock(open_files);
280 prev = open_files->prev;
281 /* lock the element after the current one */
282 if (prev != open_files)
287 /* now do the actual insertion: */
288 fio->next = open_files;
289 open_files->prev = fio;
293 /* now unlock all our locks */
294 if (prev != open_files)
296 gmx_fio_unlock(prev);
298 gmx_fio_unlock(open_files);
301 /* now unlock the big open_files mutex. */
302 tMPI_Thread_mutex_unlock(&open_file_mutex);
305 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
307 NOTE: We also assume that the open_file_mutex has been locked */
308 static void gmx_fio_remove(t_fileio *fio)
312 /* lock prev, because we're changing it */
313 gmx_fio_lock(fio->prev);
315 /* now set the prev's pointer */
316 fio->prev->next = fio->next;
317 gmx_fio_unlock(fio->prev);
319 /* with the next ptr, we can simply lock while the original was locked */
320 gmx_fio_lock(fio->next);
321 fio->next->prev = fio->prev;
322 gmx_fio_unlock(fio->next);
324 /* and make sure we point nowhere in particular */
325 fio->next = fio->prev = fio;
329 /* get the first open file, or NULL if there is none.
330 Returns a locked fio. */
331 static t_fileio *gmx_fio_get_first(void)
334 /* first lock the big open_files mutex and the dummy's mutex */
336 /* first lock the big open_files mutex. */
337 tMPI_Thread_mutex_lock(&open_file_mutex);
338 gmx_fio_make_dummy();
340 gmx_fio_lock(open_files);
341 ret = open_files->next;
344 /* check whether there were any to begin with */
345 if (ret == open_files)
347 /* after this, the open_file pointer should never change */
352 gmx_fio_lock(open_files->next);
354 gmx_fio_unlock(open_files);
360 /* get the next open file, or NULL if there is none.
361 Unlocks the previous fio and locks the next one. */
362 static t_fileio *gmx_fio_get_next(t_fileio *fio)
367 /* check if that was the last one */
368 if (fio->next == open_files)
371 tMPI_Thread_mutex_unlock(&open_file_mutex);
382 /* Stop looping through the open_files. Unlocks the global lock. */
383 static void gmx_fio_stop_getting_next(t_fileio *fio)
386 tMPI_Thread_mutex_unlock(&open_file_mutex);
392 /*****************************************************************
396 *****************************************************************/
397 t_fileio *gmx_fio_open(const char *fn, const char *mode)
399 t_fileio *fio = NULL;
402 gmx_bool bRead, bReadWrite;
405 /* sanitize the mode string */
406 if (strncmp(mode, "r+", 2) == 0)
408 strcpy(newmode, "r+");
410 else if (mode[0] == 'r')
412 strcpy(newmode, "r");
414 else if (strncmp(mode, "w+", 2) == 0)
416 strcpy(newmode, "w+");
418 else if (mode[0] == 'w')
420 strcpy(newmode, "w");
422 else if (strncmp(mode, "a+", 2) == 0)
424 strcpy(newmode, "a+");
426 else if (mode[0] == 'a')
428 strcpy(newmode, "a");
432 gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'", mode);
435 /* Check if it should be opened as a binary file */
436 if (strncmp(ftp2ftype(fn2ftp(fn)), "ASCII", 5))
438 /* Not ascii, add b to file mode */
439 if ((strchr(newmode, 'b') == NULL) && (strchr(newmode, 'B') == NULL))
441 strcat(newmode, "b");
446 tMPI_Lock_init(&(fio->mtx));
447 bRead = (newmode[0] == 'r' && newmode[1] != '+');
448 bReadWrite = (newmode[1] == '+');
453 fio->iFTP = fn2ftp(fn);
454 fio->fn = gmx_strdup(fn);
457 /* If this file type is in the list of XDR files, open it like that */
458 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
460 /* First check whether we have to make a backup,
461 * only for writing, not for read or append.
463 if (newmode[0] == 'w')
466 /* only make backups for normal gromacs */
472 /* Check whether file exists */
478 if (fn2ftp(fn) == efTNG)
480 gmx_incons("gmx_fio_open may not be used to open TNG files");
483 fio->fp = gmx_ffopen(fn, newmode);
485 /* determine the XDR direction */
486 if (newmode[0] == 'w' || newmode[0] == 'a')
488 fio->xdrmode = XDR_ENCODE;
492 fio->xdrmode = XDR_DECODE;
496 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
500 /* If it is not, open it as a regular file */
501 fio->fp = gmx_ffopen(fn, newmode);
504 /* for appending seek to end of file to make sure ftell gives correct position
505 * important for checkpointing */
506 if (newmode[0] == 'a')
508 gmx_fseek(fio->fp, 0, SEEK_END);
512 fio->bReadWrite = bReadWrite;
513 fio->bDouble = (sizeof(real) == sizeof(double));
517 /* set the reader/writer functions */
518 gmx_fio_set_iotype(fio);
520 /* and now insert this file into the list of open files. */
525 static int gmx_fio_close_locked(t_fileio *fio)
531 gmx_fatal(FARGS, "File %s closed twice!\n", fio->fn);
534 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
536 xdr_destroy(fio->xdr);
540 /* Don't close stdin and stdout! */
541 if (!fio->bStdio && fio->fp != NULL)
543 rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
551 int gmx_fio_close(t_fileio *fio)
555 /* first lock the big open_files mutex. */
556 /* We don't want two processes operating on the list at the same time */
557 tMPI_Thread_mutex_lock(&open_file_mutex);
559 if (fio->iFTP == efTNG)
561 gmx_incons("gmx_fio_close should not be called on a TNG file");
564 /* first remove it from the list */
566 rc = gmx_fio_close_locked(fio);
572 tMPI_Thread_mutex_unlock(&open_file_mutex);
577 /* close only fp but keep FIO entry. */
578 int gmx_fio_fp_close(t_fileio *fio)
582 if (!in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR) && !fio->bStdio)
584 rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
592 FILE * gmx_fio_fopen(const char *fn, const char *mode)
597 fio = gmx_fio_open(fn, mode);
605 int gmx_fio_fclose(FILE *fp)
608 t_fileio *found = NULL;
611 cur = gmx_fio_get_first();
616 rc = gmx_fio_close_locked(cur);
618 gmx_fio_stop_getting_next(cur);
623 cur = gmx_fio_get_next(cur);
629 /* internal variant of get_file_md5 that operates on a locked file */
630 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
631 unsigned char digest[])
633 /*1MB: large size important to catch almost identical files */
634 #define CPT_CHK_LEN 1048576
638 gmx_off_t seek_offset;
641 seek_offset = offset - CPT_CHK_LEN;
646 read_len = offset - seek_offset;
649 if (fio->fp && fio->bReadWrite)
651 ret = gmx_fseek(fio->fp, seek_offset, SEEK_SET);
654 gmx_fseek(fio->fp, 0, SEEK_END);
657 if (ret) /*either no fp, not readwrite, or fseek not successful */
662 snew(buf, CPT_CHK_LEN);
663 /* the read puts the file position back to offset */
664 if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
666 /* not fatal: md5sum check to prevent overwriting files
667 * works (less safe) without
671 fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
674 else if (feof(fio->fp))
677 * For long runs that checkpoint frequently but write e.g. logs
678 * infrequently we don't want to issue lots of warnings before we
679 * have written anything to the log.
683 fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
690 "\nTrying to get md5sum: Unknown reason for short read: %s\n",
694 gmx_fseek(fio->fp, 0, SEEK_END);
698 gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows
699 it gives problems otherwise*/
703 fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
708 gmx_md5_init(&state);
709 gmx_md5_append(&state, buf, read_len);
710 gmx_md5_finish(&state, digest);
719 * fio: file to compute md5 for
720 * offset: starting pointer of region to use for md5
721 * digest: return array of md5 sum
723 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
724 unsigned char digest[])
729 ret = gmx_fio_int_get_file_md5(fio, offset, digest);
735 /* The fio_mutex should ALWAYS be locked when this function is called */
736 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
740 /* Flush the file, so we are sure it is written */
741 if (gmx_fio_int_flush(fio))
746 "Cannot write file '%s'; maybe you are out of disk space?",
751 /* We cannot count on XDR being able to write 64-bit integers,
752 so separate into high/low 32-bit values.
753 In case the filesystem has 128-bit offsets we only care
754 about the first 64 bits - we'll have to fix
755 this when exabyte-size output files are common...
757 *offset = gmx_ftell(fio->fp);
762 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
765 int i, nfiles, rc, nalloc;
768 gmx_file_position_t * outputfiles;
774 /* pre-allocate 100 files */
776 snew(outputfiles, nalloc);
778 cur = gmx_fio_get_first();
781 /* Skip the checkpoint files themselves, since they could be open when
782 we call this routine... */
783 /* also skip debug files (shoud be the only iFTP==efNR) */
787 cur->iFTP != efCPT &&
791 /* This is an output file currently open for writing, add it */
792 if (nfiles == nalloc)
795 srenew(outputfiles, nalloc);
798 strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
800 /* Get the file position */
801 gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
803 outputfiles[nfiles].chksum_size
804 = gmx_fio_int_get_file_md5(cur,
805 outputfiles[nfiles].offset,
806 outputfiles[nfiles].chksum);
811 cur = gmx_fio_get_next(cur);
814 *p_outputfiles = outputfiles;
820 void gmx_fio_checktype(t_fileio *fio)
822 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
826 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
830 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
835 else if (in_ftpset(fio->iFTP, asize(ftpXML), ftpXML))
842 gmx_fatal(FARGS, "Can not read/write topologies to file type %s",
849 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
852 fio->bDouble = bDouble;
856 gmx_bool gmx_fio_getdebug(t_fileio *fio)
867 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
870 fio->bDebug = bDebug;
874 char *gmx_fio_getname(t_fileio *fio)
884 int gmx_fio_getftp(t_fileio* fio)
895 void gmx_fio_rewind(t_fileio* fio)
901 xdr_destroy(fio->xdr);
903 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
913 int gmx_fio_flush(t_fileio* fio)
918 ret = gmx_fio_int_flush(fio);
926 static int gmx_fio_int_fsync(t_fileio *fio)
934 rc = gmx_fsync(fio->fp);
936 else if (fio->xdr) /* this should normally not happen */
938 rc = gmx_fsync((FILE*) fio->xdr->x_private);
939 /* ^ is this actually OK? */
946 int gmx_fio_fsync(t_fileio *fio)
951 rc = gmx_fio_int_fsync(fio);
959 t_fileio *gmx_fio_all_output_fsync(void)
961 t_fileio *ret = NULL;
964 cur = gmx_fio_get_first();
967 /* skip debug files (shoud be the only iFTP==efNR) */
973 /* if any of them fails, return failure code */
974 int rc = gmx_fio_int_fsync(cur);
980 cur = gmx_fio_get_next(cur);
983 /* in addition, we force these to be written out too, if they're being
984 redirected. We don't check for errors because errors most likely mean
985 that they're not redirected. */
988 #if (defined(HAVE_FSYNC))
989 /* again, fahcore defines HAVE_FSYNC and fsync() */
990 fsync(STDOUT_FILENO);
991 fsync(STDERR_FILENO);
998 gmx_off_t gmx_fio_ftell(t_fileio* fio)
1005 ret = gmx_ftell(fio->fp);
1007 gmx_fio_unlock(fio);
1011 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
1018 rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
1025 gmx_fio_unlock(fio);
1029 FILE *gmx_fio_getfp(t_fileio *fio)
1038 gmx_fio_unlock(fio);
1042 XDR *gmx_fio_getxdr(t_fileio* fio)
1051 gmx_fio_unlock(fio);
1056 gmx_bool gmx_fio_getread(t_fileio* fio)
1062 gmx_fio_unlock(fio);
1067 int xtc_seek_frame(t_fileio *fio, int frame, int natoms)
1072 ret = xdr_xtc_seek_frame(frame, fio->fp, fio->xdr, natoms);
1073 gmx_fio_unlock(fio);
1078 int xtc_seek_time(t_fileio *fio, real time, int natoms, gmx_bool bSeekForwardOnly)
1083 ret = xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms, bSeekForwardOnly);
1084 gmx_fio_unlock(fio);