1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
11 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13 * Copyright (c) 2001-2004, The GROMACS development team,
14 * check out http://www.gromacs.org for more information.
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * If you want to redistribute modifications, please consider that
22 * scientific software is very special. Version control is crucial -
23 * bugs must be traceable. We will be happy to consider code for
24 * inclusion in the official distribution, but derived work must not
25 * be called official GROMACS. Details are found in the README & COPYING
26 * files - if they are missing, get the official version at www.gromacs.org.
28 * To help us fund GROMACS development, we humbly ask that you cite
29 * the papers on the package - you can find them in the top README file.
31 * For more info, check our website at http://www.gromacs.org
34 * GROningen Mixture of Alchemy and Childrens' Stories
50 #include "gmx_fatal.h"
60 #include "thread_mpi.h"
63 #include "gmxfio_int.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;
75 /* this mutex locks the open_files structure so that no two threads can
78 For now, we use this as a coarse grained lock on all file
79 insertion/deletion operations because it makes avoiding deadlocks
80 easier, and adds almost no overhead: the only overhead is during
81 opening and closing of files, or during global operations like
82 iterating along all open files. All these cases should be rare
83 during the simulation. */
84 static tMPI_Thread_mutex_t open_file_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
88 /* These simple lists define the I/O type for these files */
89 static const int ftpXDR[] =
90 { efTPR, efTRR, efEDR, efXTC, efMTX, efCPT };
91 static const int ftpASC[] =
92 { efTPA, efGRO, efPDB };
93 static const int ftpBIN[] =
96 static const int ftpXML[] =
100 const char *itemstr[eitemNR] =
102 "[header]", "[inputrec]", "[box]", "[topology]", "[coordinates]",
103 "[velocities]", "[forces]"
106 const char *eioNames[eioNR] =
108 "REAL", "INT", "GMX_STE_T", "UCHAR", "NUCHAR", "USHORT", "RVEC", "NRVEC",
114 /* Comment strings for TPA only */
115 const char *comment_str[eitemNR] = {
116 "; The header holds information on the number of atoms etc. and on whether\n"
117 "; certain items are present in the file or not.\n"
120 "; DO NOT EDIT THIS FILE BY HAND\n"
121 "; The GROMACS preprocessor performs a lot of checks on your input that\n"
122 "; you ignore when editing this. Your simulation may crash because of this\n",
123 "; The inputrec holds the parameters for MD such as the number of steps,\n"
124 "; the timestep and the cut-offs.\n",
125 "; The simulation box in nm.\n",
126 "; The topology section describes the topology of the molecules\n"
127 "; i.e. bonds, angles and dihedrals etc. and also holds the force field\n"
129 "; The atomic coordinates in nm\n",
130 "; The atomic velocities in nm/ps\n",
131 "; The forces on the atoms in nm/ps^2\n"
137 /******************************************************************
139 * Internal functions:
141 ******************************************************************/
143 static int gmx_fio_int_flush(t_fileio* fio)
149 rc = fflush(fio->fp);
153 rc = fflush((FILE *) fio->xdr->x_private);
159 /* returns TRUE if the file type ftp is in the set set */
160 static gmx_bool in_ftpset(int ftp, int nset, const int set[])
166 for (i = 0; (i < nset); i++)
179 extern void gmx_fio_set_comment(t_fileio *fio, const char *comment)
181 fio->comment = comment;
184 extern void gmx_fio_unset_comment(t_fileio *fio)
190 const char *gmx_fio_dbgstr(t_fileio *fio, const char *desc, char *buf)
194 /* set to empty string */
199 snprintf(buf, GMX_FIO_BUFLEN, " ; %s %s", fio->comment ? fio->comment : "", desc);
205 /* check the number of items given against the type */
206 void gmx_fio_check_nitem(int eio, int nitem, const char *file, int line)
208 if ((nitem != 1) && !((eio == eioNRVEC) || (eio == eioNUCHAR)))
211 "nitem (%d) may differ from 1 only for %s or %s, not for %s"
212 "(%s, %d)", nitem, eioNames[eioNUCHAR], eioNames[eioNRVEC],
213 eioNames[eio], file, line);
218 /* output a data type error. */
219 void gmx_fio_fe(t_fileio *fio, int eio, const char *desc,
220 const char *srcfile, int line)
223 gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d",
224 fio->bRead ? "read" : "write", desc, eio,
225 ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown",
230 /* set the reader/writer functions based on the file type */
231 static void gmx_fio_set_iotype(t_fileio *fio)
233 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
236 fio->iotp = &xdr_iotype;
238 gmx_fatal(FARGS, "Sorry, no XDR");
241 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
243 fio->iotp = &asc_iotype;
245 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
247 fio->iotp = &bin_iotype;
250 else if (in_ftpset(fio->iFTP, asize(ftpXML), ftpXML))
252 fio->iotp = &dummy_iotype;
257 fio->iotp = &dummy_iotype;
262 /* lock the mutex associated with this fio. This needs to be done for every
263 type of access to the fio's elements. */
264 void gmx_fio_lock(t_fileio *fio)
266 #ifdef GMX_THREAD_MPI
267 tMPI_Lock_lock(&(fio->mtx));
270 /* unlock the mutex associated with this fio. */
271 void gmx_fio_unlock(t_fileio *fio)
273 #ifdef GMX_THREAD_MPI
274 tMPI_Lock_unlock(&(fio->mtx));
278 /* make a dummy head element, assuming we locked everything. */
279 static void gmx_fio_make_dummy(void)
284 open_files->fp = NULL;
285 open_files->fn = NULL;
286 open_files->next = open_files;
287 open_files->prev = open_files;
288 #ifdef GMX_THREAD_MPI
289 tMPI_Lock_init(&(open_files->mtx));
300 /***********************************************************************
302 * FILE LIST OPERATIONS
304 ***********************************************************************/
307 /* insert a new t_fileio into the list */
308 static void gmx_fio_insert(t_fileio *fio)
311 #ifdef GMX_THREAD_MPI
312 /* first lock the big open_files mutex. */
313 tMPI_Thread_mutex_lock(&open_file_mutex);
315 /* now check whether the dummy element has been allocated,
316 and allocate it if it hasn't */
317 gmx_fio_make_dummy();
319 /* and lock the fio we got and the list's head **/
321 gmx_fio_lock(open_files);
322 prev = open_files->prev;
323 /* lock the element after the current one */
324 if (prev != open_files)
329 /* now do the actual insertion: */
330 fio->next = open_files;
331 open_files->prev = fio;
335 /* now unlock all our locks */
336 if (prev != open_files)
338 gmx_fio_unlock(prev);
340 gmx_fio_unlock(open_files);
343 #ifdef GMX_THREAD_MPI
344 /* now unlock the big open_files mutex. */
345 tMPI_Thread_mutex_unlock(&open_file_mutex);
349 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
351 NOTE: We also assume that the open_file_mutex has been locked */
352 static void gmx_fio_remove(t_fileio *fio)
356 /* lock prev, because we're changing it */
357 gmx_fio_lock(fio->prev);
359 /* now set the prev's pointer */
360 fio->prev->next = fio->next;
361 gmx_fio_unlock(fio->prev);
363 /* with the next ptr, we can simply lock while the original was locked */
364 gmx_fio_lock(fio->next);
365 fio->next->prev = fio->prev;
366 gmx_fio_unlock(fio->next);
368 /* and make sure we point nowhere in particular */
369 fio->next = fio->prev = fio;
373 /* get the first open file, or NULL if there is none.
374 Returns a locked fio. */
375 static t_fileio *gmx_fio_get_first(void)
378 /* first lock the big open_files mutex and the dummy's mutex */
380 #ifdef GMX_THREAD_MPI
381 /* first lock the big open_files mutex. */
382 tMPI_Thread_mutex_lock(&open_file_mutex);
384 gmx_fio_make_dummy();
386 gmx_fio_lock(open_files);
387 ret = open_files->next;
390 /* check whether there were any to begin with */
391 if (ret == open_files)
393 /* after this, the open_file pointer should never change */
398 gmx_fio_lock(open_files->next);
400 gmx_fio_unlock(open_files);
406 /* get the next open file, or NULL if there is none.
407 Unlocks the previous fio and locks the next one. */
408 static t_fileio *gmx_fio_get_next(t_fileio *fio)
413 /* check if that was the last one */
414 if (fio->next == open_files)
417 #ifdef GMX_THREAD_MPI
418 tMPI_Thread_mutex_unlock(&open_file_mutex);
430 /* Stop looping through the open_files. Unlocks the global lock. */
431 static void gmx_fio_stop_getting_next(t_fileio *fio)
434 #ifdef GMX_THREAD_MPI
435 tMPI_Thread_mutex_unlock(&open_file_mutex);
442 /*****************************************************************
446 *****************************************************************/
447 t_fileio *gmx_fio_open(const char *fn, const char *mode)
449 t_fileio *fio = NULL;
452 gmx_bool bRead, bReadWrite;
455 if (fn2ftp(fn) == efTPA)
457 strcpy(newmode, mode);
461 /* sanitize the mode string */
462 if (strncmp(mode, "r+", 2) == 0)
464 strcpy(newmode, "r+");
466 else if (mode[0] == 'r')
468 strcpy(newmode, "r");
470 else if (strncmp(mode, "w+", 2) == 0)
472 strcpy(newmode, "w+");
474 else if (mode[0] == 'w')
476 strcpy(newmode, "w");
478 else if (strncmp(mode, "a+", 2) == 0)
480 strcpy(newmode, "a+");
482 else if (mode[0] == 'a')
484 strcpy(newmode, "a");
488 gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'", mode);
492 /* Check if it should be opened as a binary file */
493 if (strncmp(ftp2ftype(fn2ftp(fn)), "ASCII", 5))
495 /* Not ascii, add b to file mode */
496 if ((strchr(newmode, 'b') == NULL) && (strchr(newmode, 'B') == NULL))
498 strcat(newmode, "b");
503 #ifdef GMX_THREAD_MPI
504 tMPI_Lock_init(&(fio->mtx));
506 bRead = (newmode[0] == 'r' && newmode[1] != '+');
507 bReadWrite = (newmode[1] == '+');
512 fio->iFTP = fn2ftp(fn);
513 fio->fn = strdup(fn);
516 /* If this file type is in the list of XDR files, open it like that */
517 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
519 /* First check whether we have to make a backup,
520 * only for writing, not for read or append.
522 if (newmode[0] == 'w')
525 /* only make backups for normal gromacs */
531 /* Check whether file exists */
538 fio->fp = ffopen(fn, newmode);
540 /* determine the XDR direction */
541 if (newmode[0] == 'w' || newmode[0] == 'a')
543 fio->xdrmode = XDR_ENCODE;
547 fio->xdrmode = XDR_DECODE;
551 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
555 /* If it is not, open it as a regular file */
556 fio->fp = ffopen(fn, newmode);
559 /* for appending seek to end of file to make sure ftell gives correct position
560 * important for checkpointing */
561 if (newmode[0] == 'a')
563 gmx_fseek(fio->fp, 0, SEEK_END);
568 /* Use stdin/stdout for I/O */
570 fio->fp = bRead ? stdin : stdout;
571 fio->fn = strdup("STDIO");
575 fio->bReadWrite = bReadWrite;
576 fio->bDouble = (sizeof(real) == sizeof(double));
579 fio->bLargerThan_off_t = FALSE;
581 /* set the reader/writer functions */
582 gmx_fio_set_iotype(fio);
584 /* and now insert this file into the list of open files. */
589 static int gmx_fio_close_locked(t_fileio *fio)
595 gmx_fatal(FARGS, "File %s closed twice!\n", fio->fn);
598 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
600 xdr_destroy(fio->xdr);
604 /* Don't close stdin and stdout! */
605 if (!fio->bStdio && fio->fp != NULL)
607 rc = ffclose(fio->fp); /* fclose returns 0 if happy */
615 int gmx_fio_close(t_fileio *fio)
619 #ifdef GMX_THREAD_MPI
620 /* first lock the big open_files mutex. */
621 /* We don't want two processes operating on the list at the same time */
622 tMPI_Thread_mutex_lock(&open_file_mutex);
626 /* first remove it from the list */
628 rc = gmx_fio_close_locked(fio);
634 #ifdef GMX_THREAD_MPI
635 tMPI_Thread_mutex_unlock(&open_file_mutex);
641 /* close only fp but keep FIO entry. */
642 int gmx_fio_fp_close(t_fileio *fio)
646 if (!in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR) && !fio->bStdio)
648 rc = ffclose(fio->fp); /* fclose returns 0 if happy */
656 FILE * gmx_fio_fopen(const char *fn, const char *mode)
661 fio = gmx_fio_open(fn, mode);
669 int gmx_fio_fclose(FILE *fp)
672 t_fileio *found = NULL;
675 cur = gmx_fio_get_first();
680 rc = gmx_fio_close_locked(cur);
682 gmx_fio_stop_getting_next(cur);
687 cur = gmx_fio_get_next(cur);
693 /* internal variant of get_file_md5 that operates on a locked file */
694 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
695 unsigned char digest[])
697 /*1MB: large size important to catch almost identical files */
698 #define CPT_CHK_LEN 1048576
700 unsigned char buf[CPT_CHK_LEN];
702 gmx_off_t seek_offset;
705 seek_offset = offset - CPT_CHK_LEN;
710 read_len = offset - seek_offset;
713 if (fio->fp && fio->bReadWrite)
715 ret = gmx_fseek(fio->fp, seek_offset, SEEK_SET);
718 gmx_fseek(fio->fp, 0, SEEK_END);
721 if (ret) /*either no fp, not readwrite, or fseek not successful */
726 /* the read puts the file position back to offset */
727 if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
729 /* not fatal: md5sum check to prevent overwriting files
730 * works (less safe) without
734 fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
737 else if (feof(fio->fp))
740 * For long runs that checkpoint frequently but write e.g. logs
741 * infrequently we don't want to issue lots of warnings before we
742 * have written anything to the log.
746 fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
753 "\nTrying to get md5sum: Unknown reason for short read: %s\n",
757 gmx_fseek(fio->fp, 0, SEEK_END);
761 gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows
762 it gives problems otherwise*/
766 fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
772 md5_append(&state, buf, read_len);
773 md5_finish(&state, digest);
784 * fio: file to compute md5 for
785 * offset: starting pointer of region to use for md5
786 * digest: return array of md5 sum
788 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
789 unsigned char digest[])
794 ret = gmx_fio_int_get_file_md5(fio, offset, digest);
800 /* The fio_mutex should ALWAYS be locked when this function is called */
801 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
805 /* Flush the file, so we are sure it is written */
806 if (gmx_fio_int_flush(fio))
811 "Cannot write file '%s'; maybe you are out of disk space?",
816 /* We cannot count on XDR being able to write 64-bit integers,
817 so separate into high/low 32-bit values.
818 In case the filesystem has 128-bit offsets we only care
819 about the first 64 bits - we'll have to fix
820 this when exabyte-size output files are common...
822 *offset = gmx_ftell(fio->fp);
827 int gmx_fio_check_file_position(t_fileio gmx_unused *fio)
829 /* If gmx_off_t is 4 bytes we can not store file offset > 2 GB.
830 * If we do not have ftello, we will play it safe.
832 #if (SIZEOF_GMX_OFF_T == 4 || !defined HAVE_FSEEKO)
836 gmx_fio_int_get_file_position(fio, &offset);
837 /* We have a 4 byte offset,
838 * make sure that we will detect out of range for all possible cases.
840 if (offset < 0 || offset > 2147483647)
842 fio->bLargerThan_off_t = TRUE;
850 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
853 int i, nfiles, rc, nalloc;
856 gmx_file_position_t * outputfiles;
862 /* pre-allocate 100 files */
864 snew(outputfiles, nalloc);
866 cur = gmx_fio_get_first();
869 /* Skip the checkpoint files themselves, since they could be open when
870 we call this routine... */
871 /* also skip debug files (shoud be the only iFTP==efNR) */
875 cur->iFTP != efCPT &&
879 /* This is an output file currently open for writing, add it */
880 if (nfiles == nalloc)
883 srenew(outputfiles, nalloc);
886 strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
888 /* Get the file position */
889 if (cur->bLargerThan_off_t)
891 /* -1 signals out of range */
892 outputfiles[nfiles].offset = -1;
893 outputfiles[nfiles].chksum_size = -1;
897 gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
899 outputfiles[nfiles].chksum_size
900 = gmx_fio_int_get_file_md5(cur,
901 outputfiles[nfiles].offset,
902 outputfiles[nfiles].chksum);
909 cur = gmx_fio_get_next(cur);
912 *p_outputfiles = outputfiles;
918 void gmx_fio_checktype(t_fileio *fio)
920 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
924 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
928 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
933 else if (in_ftpset(fio->iFTP, asize(ftpXML), ftpXML))
940 gmx_fatal(FARGS, "Can not read/write topologies to file type %s",
947 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
950 fio->bDouble = bDouble;
954 gmx_bool gmx_fio_getdebug(t_fileio *fio)
965 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
968 fio->bDebug = bDebug;
972 char *gmx_fio_getname(t_fileio *fio)
982 int gmx_fio_getftp(t_fileio* fio)
993 void gmx_fio_rewind(t_fileio* fio)
999 xdr_destroy(fio->xdr);
1001 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
1007 gmx_fio_unlock(fio);
1011 int gmx_fio_flush(t_fileio* fio)
1016 ret = gmx_fio_int_flush(fio);
1017 gmx_fio_unlock(fio);
1024 static int gmx_fio_int_fsync(t_fileio *fio)
1032 rc = gmx_fsync(fio->fp);
1034 else if (fio->xdr) /* this should normally not happen */
1036 rc = gmx_fsync((FILE*) fio->xdr->x_private);
1037 /* ^ is this actually OK? */
1044 int gmx_fio_fsync(t_fileio *fio)
1049 rc = gmx_fio_int_fsync(fio);
1050 gmx_fio_unlock(fio);
1057 t_fileio *gmx_fio_all_output_fsync(void)
1059 t_fileio *ret = NULL;
1062 cur = gmx_fio_get_first();
1065 /* skip debug files (shoud be the only iFTP==efNR) */
1071 /* if any of them fails, return failure code */
1072 int rc = gmx_fio_int_fsync(cur);
1073 if (rc != 0 && !ret)
1078 cur = gmx_fio_get_next(cur);
1081 /* in addition, we force these to be written out too, if they're being
1082 redirected. We don't check for errors because errors most likely mean
1083 that they're not redirected. */
1086 #if (defined(HAVE_FSYNC))
1087 /* again, fahcore defines HAVE_FSYNC and fsync() */
1088 fsync(STDOUT_FILENO);
1089 fsync(STDERR_FILENO);
1096 gmx_off_t gmx_fio_ftell(t_fileio* fio)
1103 ret = gmx_ftell(fio->fp);
1105 gmx_fio_unlock(fio);
1109 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
1116 rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
1123 gmx_fio_unlock(fio);
1127 FILE *gmx_fio_getfp(t_fileio *fio)
1136 gmx_fio_unlock(fio);
1140 XDR *gmx_fio_getxdr(t_fileio* fio)
1149 gmx_fio_unlock(fio);
1154 gmx_bool gmx_fio_getread(t_fileio* fio)
1160 gmx_fio_unlock(fio);
1165 int xtc_seek_frame(t_fileio *fio, int frame, int natoms)
1170 ret = xdr_xtc_seek_frame(frame, fio->fp, fio->xdr, natoms);
1171 gmx_fio_unlock(fio);
1176 int xtc_seek_time(t_fileio *fio, real time, int natoms, gmx_bool bSeekForwardOnly)
1181 ret = xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms, bSeekForwardOnly);
1182 gmx_fio_unlock(fio);