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
47 #include "gmx_fatal.h"
57 #include "thread_mpi.h"
60 #include "gmxfio_int.h"
62 /* This is the new improved and thread safe version of gmxfio. */
66 /* the list of open files is a linked list, with a dummy element at its head;
67 it is initialized when the first file is opened. */
68 static t_fileio *open_files = NULL;
72 /* this mutex locks the open_files structure so that no two threads can
75 For now, we use this as a coarse grained lock on all file
76 insertion/deletion operations because it makes avoiding deadlocks
77 easier, and adds almost no overhead: the only overhead is during
78 opening and closing of files, or during global operations like
79 iterating along all open files. All these cases should be rare
80 during the simulation. */
81 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, efMTX, efCPT };
88 static const int ftpASC[] =
89 { efTPA, efGRO, efPDB };
90 static const int ftpBIN[] =
93 static const int ftpXML[] =
97 const char *itemstr[eitemNR] =
98 { "[header]", "[inputrec]", "[box]", "[topology]", "[coordinates]",
99 "[velocities]", "[forces]" };
101 const char *eioNames[eioNR] =
102 { "REAL", "INT", "GMX_STE_T", "UCHAR", "NUCHAR", "USHORT", "RVEC", "NRVEC",
107 /* Comment strings for TPA only */
108 const char *comment_str[eitemNR] = {
109 "; The header holds information on the number of atoms etc. and on whether\n"
110 "; certain items are present in the file or not.\n"
113 "; DO NOT EDIT THIS FILE BY HAND\n"
114 "; The GROMACS preprocessor performs a lot of checks on your input that\n"
115 "; you ignore when editing this. Your simulation may crash because of this\n",
116 "; The inputrec holds the parameters for MD such as the number of steps,\n"
117 "; the timestep and the cut-offs.\n",
118 "; The simulation box in nm.\n",
119 "; The topology section describes the topology of the molecules\n"
120 "; i.e. bonds, angles and dihedrals etc. and also holds the force field\n"
122 "; The atomic coordinates in nm\n",
123 "; The atomic velocities in nm/ps\n",
124 "; The forces on the atoms in nm/ps^2\n" };
129 /******************************************************************
131 * Internal functions:
133 ******************************************************************/
135 static int gmx_fio_int_flush(t_fileio* fio)
141 rc = fflush(fio->fp);
145 rc = fflush((FILE *) fio->xdr->x_private);
151 /* returns TRUE if the file type ftp is in the set set */
152 static gmx_bool in_ftpset(int ftp, int nset, const int set[])
158 for (i = 0; (i < nset); i++)
167 extern void gmx_fio_set_comment(t_fileio *fio, const char *comment)
169 fio->comment=comment;
172 extern void gmx_fio_unset_comment(t_fileio *fio)
178 const char *gmx_fio_dbgstr(t_fileio *fio, const char *desc, char *buf)
182 /* set to empty string */
187 snprintf(buf, GMX_FIO_BUFLEN, " ; %s %s", fio->comment ? fio->comment : "", desc);
193 /* check the number of items given against the type */
194 void gmx_fio_check_nitem(t_fileio *fio, int eio, int nitem, const char *file,
197 if ((nitem != 1) && !((eio == eioNRVEC) || (eio == eioNUCHAR)))
199 "nitem (%d) may differ from 1 only for %s or %s, not for %s"
200 "(%s, %d)",nitem,eioNames[eioNUCHAR],eioNames[eioNRVEC],
201 eioNames[eio],file,line);
205 /* output a data type error. */
206 void gmx_fio_fe(t_fileio *fio, int eio, const char *desc,
207 const char *srcfile, int line)
210 gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d",
211 fio->bRead ? "read" : "write",desc,eio,
212 ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown",
217 /* set the reader/writer functions based on the file type */
218 static void gmx_fio_set_iotype(t_fileio *fio)
220 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
223 fio->iotp=&xdr_iotype;
225 gmx_fatal(FARGS,"Sorry, no XDR");
228 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
230 fio->iotp=&asc_iotype;
232 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
234 fio->iotp=&bin_iotype;
237 else if (in_ftpset(fio->iFTP,asize(ftpXML),ftpXML))
239 fio->iotp=&dummy_iotype;
243 fio->iotp=&dummy_iotype;
247 /* lock the mutex associated with this fio. This needs to be done for every
248 type of access to the fio's elements. */
249 void gmx_fio_lock(t_fileio *fio)
252 tMPI_Lock_lock(&(fio->mtx));
255 /* unlock the mutex associated with this fio. */
256 void gmx_fio_unlock(t_fileio *fio)
259 tMPI_Lock_unlock(&(fio->mtx));
263 /* make a dummy head element, assuming we locked everything. */
264 static void gmx_fio_make_dummy(void)
271 open_files->next=open_files;
272 open_files->prev=open_files;
274 tMPI_Lock_init(&(open_files->mtx));
285 /***********************************************************************
287 * FILE LIST OPERATIONS
289 ***********************************************************************/
292 /* insert a new t_fileio into the list */
293 static void gmx_fio_insert(t_fileio *fio)
297 /* first lock the big open_files mutex. */
298 tMPI_Thread_mutex_lock(&open_file_mutex);
300 /* now check whether the dummy element has been allocated,
301 and allocate it if it hasn't */
302 gmx_fio_make_dummy();
304 /* and lock the fio we got and the list's head **/
306 gmx_fio_lock(open_files);
307 prev=open_files->prev;
308 /* lock the element after the current one */
309 if (prev != open_files)
314 /* now do the actual insertion: */
315 fio->next=open_files;
316 open_files->prev=fio;
320 /* now unlock all our locks */
321 if (prev != open_files)
323 gmx_fio_unlock(prev);
325 gmx_fio_unlock(open_files);
329 /* now unlock the big open_files mutex. */
330 tMPI_Thread_mutex_unlock(&open_file_mutex);
334 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
336 NOTE: We also assume that the open_file_mutex has been locked */
337 static void gmx_fio_remove(t_fileio *fio)
341 /* lock prev, because we're changing it */
342 gmx_fio_lock(fio->prev);
344 /* now set the prev's pointer */
345 fio->prev->next=fio->next;
346 gmx_fio_unlock(fio->prev);
348 /* with the next ptr, we can simply lock while the original was locked */
349 gmx_fio_lock(fio->next);
350 fio->next->prev=fio->prev;
351 gmx_fio_unlock(fio->next);
353 /* and make sure we point nowhere in particular */
354 fio->next=fio->prev=fio;
358 /* get the first open file, or NULL if there is none.
359 Returns a locked fio. */
360 static t_fileio *gmx_fio_get_first(void)
363 /* first lock the big open_files mutex and the dummy's mutex */
366 /* first lock the big open_files mutex. */
367 tMPI_Thread_mutex_lock(&open_file_mutex);
369 gmx_fio_make_dummy();
371 gmx_fio_lock(open_files);
372 ret=open_files->next;
375 /* check whether there were any to begin with */
378 /* after this, the open_file pointer should never change */
383 gmx_fio_lock(open_files->next);
385 gmx_fio_unlock(open_files);
391 /* get the next open file, or NULL if there is none.
392 Unlocks the previous fio and locks the next one. */
393 static t_fileio *gmx_fio_get_next(t_fileio *fio)
398 /* check if that was the last one */
399 if (fio->next==open_files)
403 tMPI_Thread_mutex_unlock(&open_file_mutex);
415 /* Stop looping through the open_files. Unlocks the global lock. */
416 static void gmx_fio_stop_getting_next(t_fileio *fio)
420 tMPI_Thread_mutex_unlock(&open_file_mutex);
427 /*****************************************************************
431 *****************************************************************/
432 t_fileio *gmx_fio_open(const char *fn, const char *mode)
434 t_fileio *fio = NULL;
437 gmx_bool bRead, bReadWrite;
440 if (fn2ftp(fn) == efTPA)
442 strcpy(newmode, mode);
446 /* sanitize the mode string */
447 if (strncmp(mode, "r+", 2) == 0)
449 strcpy(newmode, "r+");
451 else if (mode[0] == 'r')
453 strcpy(newmode, "r");
455 else if (strncmp(mode, "w+", 2) == 0)
457 strcpy(newmode, "w+");
459 else if (mode[0] == 'w')
461 strcpy(newmode, "w");
463 else if (strncmp(mode, "a+", 2) == 0)
465 strcpy(newmode, "a+");
467 else if (mode[0] == 'a')
469 strcpy(newmode, "a");
473 gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'",mode);
477 /* Check if it should be opened as a binary file */
478 if (strncmp(ftp2ftype(fn2ftp(fn)),"ASCII",5))
480 /* Not ascii, add b to file mode */
481 if ((strchr(newmode,'b')==NULL) && (strchr(newmode,'B')==NULL))
489 tMPI_Lock_init(&(fio->mtx));
491 bRead = (newmode[0]=='r' && newmode[1]!='+');
492 bReadWrite = (newmode[1]=='+');
497 fio->iFTP = fn2ftp(fn);
498 fio->fn = strdup(fn);
501 /* If this file type is in the list of XDR files, open it like that */
502 if (in_ftpset(fio->iFTP,asize(ftpXDR),ftpXDR))
504 /* First check whether we have to make a backup,
505 * only for writing, not for read or append.
510 /* only make backups for normal gromacs */
516 /* Check whether file exists */
523 fio->fp = ffopen(fn,newmode);
525 /* determine the XDR direction */
526 if (newmode[0] == 'w' || newmode[0]=='a')
528 fio->xdrmode=XDR_ENCODE;
532 fio->xdrmode=XDR_DECODE;
536 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
540 /* If it is not, open it as a regular file */
541 fio->fp = ffopen(fn,newmode);
544 /* for appending seek to end of file to make sure ftell gives correct position
545 * important for checkpointing */
548 gmx_fseek(fio->fp, 0, SEEK_END);
553 /* Use stdin/stdout for I/O */
555 fio->fp = bRead ? stdin : stdout;
556 fio->fn = strdup("STDIO");
560 fio->bReadWrite = bReadWrite;
561 fio->bDouble= (sizeof(real) == sizeof(double));
564 fio->bLargerThan_off_t = FALSE;
566 /* set the reader/writer functions */
567 gmx_fio_set_iotype(fio);
569 /* and now insert this file into the list of open files. */
574 static int gmx_fio_close_locked(t_fileio *fio)
580 gmx_fatal(FARGS,"File %s closed twice!\n", fio->fn);
583 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
585 xdr_destroy(fio->xdr);
589 /* Don't close stdin and stdout! */
590 if (!fio->bStdio && fio->fp!=NULL)
591 rc = ffclose(fio->fp); /* fclose returns 0 if happy */
598 int gmx_fio_close(t_fileio *fio)
603 /* first lock the big open_files mutex. */
604 /* We don't want two processes operating on the list at the same time */
605 tMPI_Thread_mutex_lock(&open_file_mutex);
609 /* first remove it from the list */
611 rc=gmx_fio_close_locked(fio);
617 tMPI_Thread_mutex_unlock(&open_file_mutex);
623 /* close only fp but keep FIO entry. */
624 int gmx_fio_fp_close(t_fileio *fio)
628 if (!in_ftpset(fio->iFTP,asize(ftpXDR),ftpXDR) && !fio->bStdio)
630 rc = ffclose(fio->fp); /* fclose returns 0 if happy */
638 FILE * gmx_fio_fopen(const char *fn, const char *mode)
643 fio = gmx_fio_open(fn, mode);
651 int gmx_fio_fclose(FILE *fp)
654 t_fileio *found=NULL;
657 cur=gmx_fio_get_first();
662 rc=gmx_fio_close_locked(cur);
664 gmx_fio_stop_getting_next(cur);
667 cur=gmx_fio_get_next(cur);
673 /* internal variant of get_file_md5 that operates on a locked file */
674 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
675 unsigned char digest[])
677 /*1MB: large size important to catch almost identical files */
678 #define CPT_CHK_LEN 1048576
680 unsigned char buf[CPT_CHK_LEN];
682 gmx_off_t seek_offset;
685 seek_offset = offset - CPT_CHK_LEN;
690 read_len = offset - seek_offset;
693 if (fio->fp && fio->bReadWrite)
695 ret=gmx_fseek(fio->fp, seek_offset, SEEK_SET);
698 gmx_fseek(fio->fp, 0, SEEK_END);
701 if (ret) /*either no fp, not readwrite, or fseek not successful */
706 /* the read puts the file position back to offset */
707 if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
709 /* not fatal: md5sum check to prevent overwriting files
710 * works (less safe) without
714 fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
717 else if (feof(fio->fp))
720 * For long runs that checkpoint frequently but write e.g. logs
721 * infrequently we don't want to issue lots of warnings before we
722 * have written anything to the log.
726 fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
733 "\nTrying to get md5sum: Unknown reason for short read: %s\n",
737 gmx_fseek(fio->fp, 0, SEEK_END);
741 gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows
742 it gives problems otherwise*/
746 fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
752 md5_append(&state, buf, read_len);
753 md5_finish(&state, digest);
764 * fio: file to compute md5 for
765 * offset: starting pointer of region to use for md5
766 * digest: return array of md5 sum
768 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
769 unsigned char digest[])
774 ret=gmx_fio_int_get_file_md5(fio, offset, digest);
780 /* The fio_mutex should ALWAYS be locked when this function is called */
781 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
785 /* Flush the file, so we are sure it is written */
786 if (gmx_fio_int_flush(fio))
791 "Cannot write file '%s'; maybe you are out of disk space or quota?",
796 /* We cannot count on XDR being able to write 64-bit integers,
797 so separate into high/low 32-bit values.
798 In case the filesystem has 128-bit offsets we only care
799 about the first 64 bits - we'll have to fix
800 this when exabyte-size output files are common...
802 *offset=gmx_ftell(fio->fp);
807 int gmx_fio_check_file_position(t_fileio *fio)
809 /* If gmx_off_t is 4 bytes we can not store file offset > 2 GB.
810 * If we do not have ftello, we will play it safe.
812 #if (SIZEOF_GMX_OFF_T == 4 || !defined HAVE_FSEEKO)
816 gmx_fio_int_get_file_position(fio,&offset);
817 /* We have a 4 byte offset,
818 * make sure that we will detect out of range for all possible cases.
820 if (offset < 0 || offset > 2147483647)
822 fio->bLargerThan_off_t = TRUE;
830 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
833 int i, nfiles, rc, nalloc;
836 gmx_file_position_t * outputfiles;
842 /* pre-allocate 100 files */
844 snew(outputfiles,nalloc);
846 cur=gmx_fio_get_first();
849 /* Skip the checkpoint files themselves, since they could be open when
850 we call this routine... */
851 /* also skip debug files (shoud be the only iFTP==efNR) */
855 cur->iFTP != efCPT &&
859 /* This is an output file currently open for writing, add it */
860 if (nfiles == nalloc)
863 srenew(outputfiles,nalloc);
866 strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
868 /* Get the file position */
869 if (cur->bLargerThan_off_t)
871 /* -1 signals out of range */
872 outputfiles[nfiles].offset = -1;
873 outputfiles[nfiles].chksum_size = -1;
877 gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
879 outputfiles[nfiles].chksum_size
880 = gmx_fio_int_get_file_md5(cur,
881 outputfiles[nfiles].offset,
882 outputfiles[nfiles].chksum);
889 cur=gmx_fio_get_next(cur);
892 *p_outputfiles = outputfiles;
898 void gmx_fio_checktype(t_fileio *fio)
900 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
904 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
908 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
913 else if (in_ftpset(fio->iFTP,asize(ftpXML),ftpXML))
919 gmx_fatal(FARGS, "Can not read/write topologies to file type %s",
925 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
928 fio->bDouble = bDouble;
932 gmx_bool gmx_fio_getdebug(t_fileio *fio)
943 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
946 fio->bDebug = bDebug;
950 char *gmx_fio_getname(t_fileio *fio)
960 int gmx_fio_getftp(t_fileio* fio)
971 void gmx_fio_rewind(t_fileio* fio)
977 xdr_destroy(fio->xdr);
979 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
989 int gmx_fio_flush(t_fileio* fio)
994 ret=gmx_fio_int_flush(fio);
1002 static int gmx_fio_int_fsync(t_fileio *fio)
1010 rc=gmx_fsync(fio->fp);
1012 else if (fio->xdr) /* this should normally not happen */
1014 rc=gmx_fsync((FILE*) fio->xdr->x_private);
1015 /* ^ is this actually OK? */
1022 int gmx_fio_fsync(t_fileio *fio)
1027 rc=gmx_fio_int_fsync(fio);
1028 gmx_fio_unlock(fio);
1035 t_fileio *gmx_fio_all_output_fsync(void)
1040 cur=gmx_fio_get_first();
1043 /* skip debug files (shoud be the only iFTP==efNR) */
1049 /* if any of them fails, return failure code */
1050 int rc=gmx_fio_int_fsync(cur);
1051 if (rc != 0 && !ret)
1056 cur=gmx_fio_get_next(cur);
1059 /* in addition, we force these to be written out too, if they're being
1060 redirected. We don't check for errors because errors most likely mean
1061 that they're not redirected. */
1064 #if (defined(HAVE_FSYNC))
1065 /* again, fahcore defines HAVE_FSYNC and fsync() */
1066 fsync(STDOUT_FILENO);
1067 fsync(STDERR_FILENO);
1074 gmx_off_t gmx_fio_ftell(t_fileio* fio)
1080 ret = gmx_ftell(fio->fp);
1081 gmx_fio_unlock(fio);
1085 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
1092 rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
1099 gmx_fio_unlock(fio);
1103 FILE *gmx_fio_getfp(t_fileio *fio)
1110 gmx_fio_unlock(fio);
1114 XDR *gmx_fio_getxdr(t_fileio* fio)
1121 gmx_fio_unlock(fio);
1126 gmx_bool gmx_fio_getread(t_fileio* fio)
1132 gmx_fio_unlock(fio);
1137 int xtc_seek_frame(t_fileio *fio, int frame, int natoms)
1142 ret=xdr_xtc_seek_frame(frame, fio->fp, fio->xdr, natoms);
1143 gmx_fio_unlock(fio);
1148 int xtc_seek_time(t_fileio *fio, real time, int natoms)
1153 ret=xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms);
1154 gmx_fio_unlock(fio);