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/utility/fatalerror.h"
59 #include "gromacs/utility/futil.h"
60 #include "gromacs/utility/smalloc.h"
62 #include "gmxfio-impl.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;
84 /******************************************************************
88 ******************************************************************/
90 static int gmx_fio_int_flush(t_fileio* fio)
100 rc = fflush((FILE *) fio->xdr->x_private);
106 /* lock the mutex associated with this fio. This needs to be done for every
107 type of access to the fio's elements. */
108 void gmx_fio_lock(t_fileio *fio)
110 tMPI_Lock_lock(&(fio->mtx));
112 /* unlock the mutex associated with this fio. */
113 void gmx_fio_unlock(t_fileio *fio)
115 tMPI_Lock_unlock(&(fio->mtx));
118 /* make a dummy head element, assuming we locked everything. */
119 static void gmx_fio_make_dummy(void)
124 open_files->fp = NULL;
125 open_files->fn = NULL;
126 open_files->next = open_files;
127 open_files->prev = open_files;
128 tMPI_Lock_init(&(open_files->mtx));
138 /***********************************************************************
140 * FILE LIST OPERATIONS
142 ***********************************************************************/
145 /* insert a new t_fileio into the list */
146 static void gmx_fio_insert(t_fileio *fio)
149 /* first lock the big open_files mutex. */
150 tMPI_Thread_mutex_lock(&open_file_mutex);
151 /* now check whether the dummy element has been allocated,
152 and allocate it if it hasn't */
153 gmx_fio_make_dummy();
155 /* and lock the fio we got and the list's head **/
157 gmx_fio_lock(open_files);
158 prev = open_files->prev;
159 /* lock the element after the current one */
160 if (prev != open_files)
165 /* now do the actual insertion: */
166 fio->next = open_files;
167 open_files->prev = fio;
171 /* now unlock all our locks */
172 if (prev != open_files)
174 gmx_fio_unlock(prev);
176 gmx_fio_unlock(open_files);
179 /* now unlock the big open_files mutex. */
180 tMPI_Thread_mutex_unlock(&open_file_mutex);
183 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
185 NOTE: We also assume that the open_file_mutex has been locked */
186 static void gmx_fio_remove(t_fileio *fio)
190 /* lock prev, because we're changing it */
191 gmx_fio_lock(fio->prev);
193 /* now set the prev's pointer */
194 fio->prev->next = fio->next;
195 gmx_fio_unlock(fio->prev);
197 /* with the next ptr, we can simply lock while the original was locked */
198 gmx_fio_lock(fio->next);
199 fio->next->prev = fio->prev;
200 gmx_fio_unlock(fio->next);
202 /* and make sure we point nowhere in particular */
203 fio->next = fio->prev = fio;
207 /* get the first open file, or NULL if there is none.
208 Returns a locked fio. */
209 static t_fileio *gmx_fio_get_first(void)
212 /* first lock the big open_files mutex and the dummy's mutex */
214 /* first lock the big open_files mutex. */
215 tMPI_Thread_mutex_lock(&open_file_mutex);
216 gmx_fio_make_dummy();
218 gmx_fio_lock(open_files);
219 ret = open_files->next;
222 /* check whether there were any to begin with */
223 if (ret == open_files)
225 /* after this, the open_file pointer should never change */
230 gmx_fio_lock(open_files->next);
232 gmx_fio_unlock(open_files);
238 /* get the next open file, or NULL if there is none.
239 Unlocks the previous fio and locks the next one. */
240 static t_fileio *gmx_fio_get_next(t_fileio *fio)
245 /* check if that was the last one */
246 if (fio->next == open_files)
249 tMPI_Thread_mutex_unlock(&open_file_mutex);
260 /* Stop looping through the open_files. Unlocks the global lock. */
261 static void gmx_fio_stop_getting_next(t_fileio *fio)
264 tMPI_Thread_mutex_unlock(&open_file_mutex);
270 /*****************************************************************
274 *****************************************************************/
275 t_fileio *gmx_fio_open(const char *fn, const char *mode)
277 t_fileio *fio = NULL;
280 gmx_bool bRead, bReadWrite;
283 /* sanitize the mode string */
284 if (strncmp(mode, "r+", 2) == 0)
286 strcpy(newmode, "r+");
288 else if (mode[0] == 'r')
290 strcpy(newmode, "r");
292 else if (strncmp(mode, "w+", 2) == 0)
294 strcpy(newmode, "w+");
296 else if (mode[0] == 'w')
298 strcpy(newmode, "w");
300 else if (strncmp(mode, "a+", 2) == 0)
302 strcpy(newmode, "a+");
304 else if (mode[0] == 'a')
306 strcpy(newmode, "a");
310 gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'", mode);
313 /* Check if it should be opened as a binary file */
314 if (!ftp_is_text(fn2ftp(fn)))
316 /* Not ascii, add b to file mode */
317 if ((strchr(newmode, 'b') == NULL) && (strchr(newmode, 'B') == NULL))
319 strcat(newmode, "b");
324 tMPI_Lock_init(&(fio->mtx));
325 bRead = (newmode[0] == 'r' && newmode[1] != '+');
326 bReadWrite = (newmode[1] == '+');
331 if (fn2ftp(fn) == efTNG)
333 gmx_incons("gmx_fio_open may not be used to open TNG files");
335 fio->iFTP = fn2ftp(fn);
336 fio->fn = gmx_strdup(fn);
338 /* If this file type is in the list of XDR files, open it like that */
339 if (ftp_is_xdr(fio->iFTP))
341 /* First check whether we have to make a backup,
342 * only for writing, not for read or append.
344 if (newmode[0] == 'w')
347 /* only make backups for normal gromacs */
353 /* Check whether file exists */
360 fio->fp = gmx_ffopen(fn, newmode);
362 /* determine the XDR direction */
363 if (newmode[0] == 'w' || newmode[0] == 'a')
365 fio->xdrmode = XDR_ENCODE;
369 fio->xdrmode = XDR_DECODE;
373 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
377 /* If it is not, open it as a regular file */
378 fio->fp = gmx_ffopen(fn, newmode);
381 /* for appending seek to end of file to make sure ftell gives correct position
382 * important for checkpointing */
383 if (newmode[0] == 'a')
385 gmx_fseek(fio->fp, 0, SEEK_END);
389 fio->bReadWrite = bReadWrite;
390 fio->bDouble = (sizeof(real) == sizeof(double));
394 /* and now insert this file into the list of open files. */
399 static int gmx_fio_close_locked(t_fileio *fio)
405 gmx_fatal(FARGS, "File %s closed twice!\n", fio->fn);
408 if (ftp_is_xdr(fio->iFTP))
410 xdr_destroy(fio->xdr);
416 rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
424 int gmx_fio_close(t_fileio *fio)
428 /* first lock the big open_files mutex. */
429 /* We don't want two processes operating on the list at the same time */
430 tMPI_Thread_mutex_lock(&open_file_mutex);
432 if (fio->iFTP == efTNG)
434 gmx_incons("gmx_fio_close should not be called on a TNG file");
437 /* first remove it from the list */
439 rc = gmx_fio_close_locked(fio);
445 tMPI_Thread_mutex_unlock(&open_file_mutex);
450 /* close only fp but keep FIO entry. */
451 int gmx_fio_fp_close(t_fileio *fio)
455 if (!ftp_is_xdr(fio->iFTP))
457 rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
465 FILE * gmx_fio_fopen(const char *fn, const char *mode)
470 fio = gmx_fio_open(fn, mode);
478 int gmx_fio_fclose(FILE *fp)
481 t_fileio *found = NULL;
484 cur = gmx_fio_get_first();
489 rc = gmx_fio_close_locked(cur);
491 gmx_fio_stop_getting_next(cur);
496 cur = gmx_fio_get_next(cur);
502 /* internal variant of get_file_md5 that operates on a locked file */
503 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
504 unsigned char digest[])
506 /*1MB: large size important to catch almost identical files */
507 #define CPT_CHK_LEN 1048576
511 gmx_off_t seek_offset;
514 seek_offset = offset - CPT_CHK_LEN;
519 read_len = offset - seek_offset;
522 if (fio->fp && fio->bReadWrite)
524 ret = gmx_fseek(fio->fp, seek_offset, SEEK_SET);
527 gmx_fseek(fio->fp, 0, SEEK_END);
530 if (ret) /*either no fp, not readwrite, or fseek not successful */
535 snew(buf, CPT_CHK_LEN);
536 /* the read puts the file position back to offset */
537 if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
539 /* not fatal: md5sum check to prevent overwriting files
540 * works (less safe) without
544 fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
547 else if (feof(fio->fp))
550 * For long runs that checkpoint frequently but write e.g. logs
551 * infrequently we don't want to issue lots of warnings before we
552 * have written anything to the log.
556 fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
563 "\nTrying to get md5sum: Unknown reason for short read: %s\n",
567 gmx_fseek(fio->fp, 0, SEEK_END);
571 gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows
572 it gives problems otherwise*/
576 fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
581 gmx_md5_init(&state);
582 gmx_md5_append(&state, buf, read_len);
583 gmx_md5_finish(&state, digest);
592 * fio: file to compute md5 for
593 * offset: starting pointer of region to use for md5
594 * digest: return array of md5 sum
596 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
597 unsigned char digest[])
602 ret = gmx_fio_int_get_file_md5(fio, offset, digest);
608 /* The fio_mutex should ALWAYS be locked when this function is called */
609 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
613 /* Flush the file, so we are sure it is written */
614 if (gmx_fio_int_flush(fio))
619 "Cannot write file '%s'; maybe you are out of disk space?",
624 /* We cannot count on XDR being able to write 64-bit integers,
625 so separate into high/low 32-bit values.
626 In case the filesystem has 128-bit offsets we only care
627 about the first 64 bits - we'll have to fix
628 this when exabyte-size output files are common...
630 *offset = gmx_ftell(fio->fp);
635 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
638 int i, nfiles, rc, nalloc;
641 gmx_file_position_t * outputfiles;
647 /* pre-allocate 100 files */
649 snew(outputfiles, nalloc);
651 cur = gmx_fio_get_first();
654 /* Skip the checkpoint files themselves, since they could be open when
655 we call this routine... */
656 if (cur->bOpen && !cur->bRead && cur->iFTP != efCPT)
659 /* This is an output file currently open for writing, add it */
660 if (nfiles == nalloc)
663 srenew(outputfiles, nalloc);
666 strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
668 /* Get the file position */
669 gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
671 outputfiles[nfiles].chksum_size
672 = gmx_fio_int_get_file_md5(cur,
673 outputfiles[nfiles].offset,
674 outputfiles[nfiles].chksum);
679 cur = gmx_fio_get_next(cur);
682 *p_outputfiles = outputfiles;
688 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
691 fio->bDouble = bDouble;
695 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
698 fio->bDebug = bDebug;
702 char *gmx_fio_getname(t_fileio *fio)
712 int gmx_fio_getftp(t_fileio* fio)
723 void gmx_fio_rewind(t_fileio* fio)
729 xdr_destroy(fio->xdr);
731 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
741 int gmx_fio_flush(t_fileio* fio)
746 ret = gmx_fio_int_flush(fio);
754 static int gmx_fio_int_fsync(t_fileio *fio)
762 rc = gmx_fsync(fio->fp);
764 else if (fio->xdr) /* this should normally not happen */
766 rc = gmx_fsync((FILE*) fio->xdr->x_private);
767 /* ^ is this actually OK? */
774 int gmx_fio_fsync(t_fileio *fio)
779 rc = gmx_fio_int_fsync(fio);
787 t_fileio *gmx_fio_all_output_fsync(void)
789 t_fileio *ret = NULL;
792 cur = gmx_fio_get_first();
795 if (cur->bOpen && !cur->bRead)
797 /* if any of them fails, return failure code */
798 int rc = gmx_fio_int_fsync(cur);
804 cur = gmx_fio_get_next(cur);
807 /* in addition, we force these to be written out too, if they're being
808 redirected. We don't check for errors because errors most likely mean
809 that they're not redirected. */
812 #if (defined(HAVE_FSYNC))
813 /* again, fahcore defines HAVE_FSYNC and fsync() */
814 fsync(STDOUT_FILENO);
815 fsync(STDERR_FILENO);
822 gmx_off_t gmx_fio_ftell(t_fileio* fio)
829 ret = gmx_ftell(fio->fp);
835 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
842 rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
853 FILE *gmx_fio_getfp(t_fileio *fio)
866 gmx_bool gmx_fio_getread(t_fileio* fio)
877 int xtc_seek_time(t_fileio *fio, real time, int natoms, gmx_bool bSeekForwardOnly)
882 ret = xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms, bSeekForwardOnly);