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] =
101 { "[header]", "[inputrec]", "[box]", "[topology]", "[coordinates]",
102 "[velocities]", "[forces]" };
104 const char *eioNames[eioNR] =
105 { "REAL", "INT", "GMX_STE_T", "UCHAR", "NUCHAR", "USHORT", "RVEC", "NRVEC",
110 /* Comment strings for TPA only */
111 const char *comment_str[eitemNR] = {
112 "; The header holds information on the number of atoms etc. and on whether\n"
113 "; certain items are present in the file or not.\n"
116 "; DO NOT EDIT THIS FILE BY HAND\n"
117 "; The GROMACS preprocessor performs a lot of checks on your input that\n"
118 "; you ignore when editing this. Your simulation may crash because of this\n",
119 "; The inputrec holds the parameters for MD such as the number of steps,\n"
120 "; the timestep and the cut-offs.\n",
121 "; The simulation box in nm.\n",
122 "; The topology section describes the topology of the molecules\n"
123 "; i.e. bonds, angles and dihedrals etc. and also holds the force field\n"
125 "; The atomic coordinates in nm\n",
126 "; The atomic velocities in nm/ps\n",
127 "; The forces on the atoms in nm/ps^2\n" };
132 /******************************************************************
134 * Internal functions:
136 ******************************************************************/
138 static int gmx_fio_int_flush(t_fileio* fio)
144 rc = fflush(fio->fp);
148 rc = fflush((FILE *) fio->xdr->x_private);
154 /* returns TRUE if the file type ftp is in the set set */
155 static gmx_bool in_ftpset(int ftp, int nset, const int set[])
161 for (i = 0; (i < nset); i++)
170 extern void gmx_fio_set_comment(t_fileio *fio, const char *comment)
172 fio->comment=comment;
175 extern void gmx_fio_unset_comment(t_fileio *fio)
181 const char *gmx_fio_dbgstr(t_fileio *fio, const char *desc, char *buf)
185 /* set to empty string */
190 snprintf(buf, GMX_FIO_BUFLEN, " ; %s %s", fio->comment ? fio->comment : "", desc);
196 /* check the number of items given against the type */
197 void gmx_fio_check_nitem(t_fileio *fio, int eio, int nitem, const char *file,
200 if ((nitem != 1) && !((eio == eioNRVEC) || (eio == eioNUCHAR)))
202 "nitem (%d) may differ from 1 only for %s or %s, not for %s"
203 "(%s, %d)",nitem,eioNames[eioNUCHAR],eioNames[eioNRVEC],
204 eioNames[eio],file,line);
208 /* output a data type error. */
209 void gmx_fio_fe(t_fileio *fio, int eio, const char *desc,
210 const char *srcfile, int line)
213 gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d",
214 fio->bRead ? "read" : "write",desc,eio,
215 ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown",
220 /* set the reader/writer functions based on the file type */
221 static void gmx_fio_set_iotype(t_fileio *fio)
223 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
226 fio->iotp=&xdr_iotype;
228 gmx_fatal(FARGS,"Sorry, no XDR");
231 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
233 fio->iotp=&asc_iotype;
235 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
237 fio->iotp=&bin_iotype;
240 else if (in_ftpset(fio->iFTP,asize(ftpXML),ftpXML))
242 fio->iotp=&dummy_iotype;
246 fio->iotp=&dummy_iotype;
250 /* lock the mutex associated with this fio. This needs to be done for every
251 type of access to the fio's elements. */
252 void gmx_fio_lock(t_fileio *fio)
254 #ifdef GMX_THREAD_MPI
255 tMPI_Lock_lock(&(fio->mtx));
258 /* unlock the mutex associated with this fio. */
259 void gmx_fio_unlock(t_fileio *fio)
261 #ifdef GMX_THREAD_MPI
262 tMPI_Lock_unlock(&(fio->mtx));
266 /* make a dummy head element, assuming we locked everything. */
267 static void gmx_fio_make_dummy(void)
274 open_files->next=open_files;
275 open_files->prev=open_files;
276 #ifdef GMX_THREAD_MPI
277 tMPI_Lock_init(&(open_files->mtx));
288 /***********************************************************************
290 * FILE LIST OPERATIONS
292 ***********************************************************************/
295 /* insert a new t_fileio into the list */
296 static void gmx_fio_insert(t_fileio *fio)
299 #ifdef GMX_THREAD_MPI
300 /* first lock the big open_files mutex. */
301 tMPI_Thread_mutex_lock(&open_file_mutex);
303 /* now check whether the dummy element has been allocated,
304 and allocate it if it hasn't */
305 gmx_fio_make_dummy();
307 /* and lock the fio we got and the list's head **/
309 gmx_fio_lock(open_files);
310 prev=open_files->prev;
311 /* lock the element after the current one */
312 if (prev != open_files)
317 /* now do the actual insertion: */
318 fio->next=open_files;
319 open_files->prev=fio;
323 /* now unlock all our locks */
324 if (prev != open_files)
326 gmx_fio_unlock(prev);
328 gmx_fio_unlock(open_files);
331 #ifdef GMX_THREAD_MPI
332 /* now unlock the big open_files mutex. */
333 tMPI_Thread_mutex_unlock(&open_file_mutex);
337 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
339 NOTE: We also assume that the open_file_mutex has been locked */
340 static void gmx_fio_remove(t_fileio *fio)
344 /* lock prev, because we're changing it */
345 gmx_fio_lock(fio->prev);
347 /* now set the prev's pointer */
348 fio->prev->next=fio->next;
349 gmx_fio_unlock(fio->prev);
351 /* with the next ptr, we can simply lock while the original was locked */
352 gmx_fio_lock(fio->next);
353 fio->next->prev=fio->prev;
354 gmx_fio_unlock(fio->next);
356 /* and make sure we point nowhere in particular */
357 fio->next=fio->prev=fio;
361 /* get the first open file, or NULL if there is none.
362 Returns a locked fio. */
363 static t_fileio *gmx_fio_get_first(void)
366 /* first lock the big open_files mutex and the dummy's mutex */
368 #ifdef GMX_THREAD_MPI
369 /* first lock the big open_files mutex. */
370 tMPI_Thread_mutex_lock(&open_file_mutex);
372 gmx_fio_make_dummy();
374 gmx_fio_lock(open_files);
375 ret=open_files->next;
378 /* check whether there were any to begin with */
381 /* after this, the open_file pointer should never change */
386 gmx_fio_lock(open_files->next);
388 gmx_fio_unlock(open_files);
394 /* get the next open file, or NULL if there is none.
395 Unlocks the previous fio and locks the next one. */
396 static t_fileio *gmx_fio_get_next(t_fileio *fio)
401 /* check if that was the last one */
402 if (fio->next==open_files)
405 #ifdef GMX_THREAD_MPI
406 tMPI_Thread_mutex_unlock(&open_file_mutex);
418 /* Stop looping through the open_files. Unlocks the global lock. */
419 static void gmx_fio_stop_getting_next(t_fileio *fio)
422 #ifdef GMX_THREAD_MPI
423 tMPI_Thread_mutex_unlock(&open_file_mutex);
430 /*****************************************************************
434 *****************************************************************/
435 t_fileio *gmx_fio_open(const char *fn, const char *mode)
437 t_fileio *fio = NULL;
440 gmx_bool bRead, bReadWrite;
443 if (fn2ftp(fn) == efTPA)
445 strcpy(newmode, mode);
449 /* sanitize the mode string */
450 if (strncmp(mode, "r+", 2) == 0)
452 strcpy(newmode, "r+");
454 else if (mode[0] == 'r')
456 strcpy(newmode, "r");
458 else if (strncmp(mode, "w+", 2) == 0)
460 strcpy(newmode, "w+");
462 else if (mode[0] == 'w')
464 strcpy(newmode, "w");
466 else if (strncmp(mode, "a+", 2) == 0)
468 strcpy(newmode, "a+");
470 else if (mode[0] == 'a')
472 strcpy(newmode, "a");
476 gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'",mode);
480 /* Check if it should be opened as a binary file */
481 if (strncmp(ftp2ftype(fn2ftp(fn)),"ASCII",5))
483 /* Not ascii, add b to file mode */
484 if ((strchr(newmode,'b')==NULL) && (strchr(newmode,'B')==NULL))
491 #ifdef GMX_THREAD_MPI
492 tMPI_Lock_init(&(fio->mtx));
494 bRead = (newmode[0]=='r' && newmode[1]!='+');
495 bReadWrite = (newmode[1]=='+');
500 fio->iFTP = fn2ftp(fn);
501 fio->fn = strdup(fn);
504 /* If this file type is in the list of XDR files, open it like that */
505 if (in_ftpset(fio->iFTP,asize(ftpXDR),ftpXDR))
507 /* First check whether we have to make a backup,
508 * only for writing, not for read or append.
513 /* only make backups for normal gromacs */
519 /* Check whether file exists */
526 fio->fp = ffopen(fn,newmode);
528 /* determine the XDR direction */
529 if (newmode[0] == 'w' || newmode[0]=='a')
531 fio->xdrmode=XDR_ENCODE;
535 fio->xdrmode=XDR_DECODE;
539 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
543 /* If it is not, open it as a regular file */
544 fio->fp = ffopen(fn,newmode);
547 /* for appending seek to end of file to make sure ftell gives correct position
548 * important for checkpointing */
551 gmx_fseek(fio->fp, 0, SEEK_END);
556 /* Use stdin/stdout for I/O */
558 fio->fp = bRead ? stdin : stdout;
559 fio->fn = strdup("STDIO");
563 fio->bReadWrite = bReadWrite;
564 fio->bDouble= (sizeof(real) == sizeof(double));
567 fio->bLargerThan_off_t = FALSE;
569 /* set the reader/writer functions */
570 gmx_fio_set_iotype(fio);
572 /* and now insert this file into the list of open files. */
577 static int gmx_fio_close_locked(t_fileio *fio)
583 gmx_fatal(FARGS,"File %s closed twice!\n", fio->fn);
586 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
588 xdr_destroy(fio->xdr);
592 /* Don't close stdin and stdout! */
593 if (!fio->bStdio && fio->fp!=NULL)
594 rc = ffclose(fio->fp); /* fclose returns 0 if happy */
601 int gmx_fio_close(t_fileio *fio)
605 #ifdef GMX_THREAD_MPI
606 /* first lock the big open_files mutex. */
607 /* We don't want two processes operating on the list at the same time */
608 tMPI_Thread_mutex_lock(&open_file_mutex);
612 /* first remove it from the list */
614 rc=gmx_fio_close_locked(fio);
620 #ifdef GMX_THREAD_MPI
621 tMPI_Thread_mutex_unlock(&open_file_mutex);
627 /* close only fp but keep FIO entry. */
628 int gmx_fio_fp_close(t_fileio *fio)
632 if (!in_ftpset(fio->iFTP,asize(ftpXDR),ftpXDR) && !fio->bStdio)
634 rc = ffclose(fio->fp); /* fclose returns 0 if happy */
642 FILE * gmx_fio_fopen(const char *fn, const char *mode)
647 fio = gmx_fio_open(fn, mode);
655 int gmx_fio_fclose(FILE *fp)
658 t_fileio *found=NULL;
661 cur=gmx_fio_get_first();
666 rc=gmx_fio_close_locked(cur);
668 gmx_fio_stop_getting_next(cur);
673 cur=gmx_fio_get_next(cur);
679 /* internal variant of get_file_md5 that operates on a locked file */
680 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
681 unsigned char digest[])
683 /*1MB: large size important to catch almost identical files */
684 #define CPT_CHK_LEN 1048576
686 unsigned char buf[CPT_CHK_LEN];
688 gmx_off_t seek_offset;
691 seek_offset = offset - CPT_CHK_LEN;
696 read_len = offset - seek_offset;
699 if (fio->fp && fio->bReadWrite)
701 ret=gmx_fseek(fio->fp, seek_offset, SEEK_SET);
704 gmx_fseek(fio->fp, 0, SEEK_END);
707 if (ret) /*either no fp, not readwrite, or fseek not successful */
712 /* the read puts the file position back to offset */
713 if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
715 /* not fatal: md5sum check to prevent overwriting files
716 * works (less safe) without
720 fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
723 else if (feof(fio->fp))
726 * For long runs that checkpoint frequently but write e.g. logs
727 * infrequently we don't want to issue lots of warnings before we
728 * have written anything to the log.
732 fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
739 "\nTrying to get md5sum: Unknown reason for short read: %s\n",
743 gmx_fseek(fio->fp, 0, SEEK_END);
747 gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows
748 it gives problems otherwise*/
752 fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
758 md5_append(&state, buf, read_len);
759 md5_finish(&state, digest);
770 * fio: file to compute md5 for
771 * offset: starting pointer of region to use for md5
772 * digest: return array of md5 sum
774 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
775 unsigned char digest[])
780 ret=gmx_fio_int_get_file_md5(fio, offset, digest);
786 /* The fio_mutex should ALWAYS be locked when this function is called */
787 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
791 /* Flush the file, so we are sure it is written */
792 if (gmx_fio_int_flush(fio))
797 "Cannot write file '%s'; maybe you are out of disk space?",
802 /* We cannot count on XDR being able to write 64-bit integers,
803 so separate into high/low 32-bit values.
804 In case the filesystem has 128-bit offsets we only care
805 about the first 64 bits - we'll have to fix
806 this when exabyte-size output files are common...
808 *offset=gmx_ftell(fio->fp);
813 int gmx_fio_check_file_position(t_fileio *fio)
815 /* If gmx_off_t is 4 bytes we can not store file offset > 2 GB.
816 * If we do not have ftello, we will play it safe.
818 #if (SIZEOF_GMX_OFF_T == 4 || !defined HAVE_FSEEKO)
822 gmx_fio_int_get_file_position(fio,&offset);
823 /* We have a 4 byte offset,
824 * make sure that we will detect out of range for all possible cases.
826 if (offset < 0 || offset > 2147483647)
828 fio->bLargerThan_off_t = TRUE;
836 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
839 int i, nfiles, rc, nalloc;
842 gmx_file_position_t * outputfiles;
848 /* pre-allocate 100 files */
850 snew(outputfiles,nalloc);
852 cur=gmx_fio_get_first();
855 /* Skip the checkpoint files themselves, since they could be open when
856 we call this routine... */
857 /* also skip debug files (shoud be the only iFTP==efNR) */
861 cur->iFTP != efCPT &&
865 /* This is an output file currently open for writing, add it */
866 if (nfiles == nalloc)
869 srenew(outputfiles,nalloc);
872 strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
874 /* Get the file position */
875 if (cur->bLargerThan_off_t)
877 /* -1 signals out of range */
878 outputfiles[nfiles].offset = -1;
879 outputfiles[nfiles].chksum_size = -1;
883 gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
885 outputfiles[nfiles].chksum_size
886 = gmx_fio_int_get_file_md5(cur,
887 outputfiles[nfiles].offset,
888 outputfiles[nfiles].chksum);
895 cur=gmx_fio_get_next(cur);
898 *p_outputfiles = outputfiles;
904 void gmx_fio_checktype(t_fileio *fio)
906 if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
910 else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
914 else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
919 else if (in_ftpset(fio->iFTP,asize(ftpXML),ftpXML))
925 gmx_fatal(FARGS, "Can not read/write topologies to file type %s",
931 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
934 fio->bDouble = bDouble;
938 gmx_bool gmx_fio_getdebug(t_fileio *fio)
949 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
952 fio->bDebug = bDebug;
956 char *gmx_fio_getname(t_fileio *fio)
966 int gmx_fio_getftp(t_fileio* fio)
977 void gmx_fio_rewind(t_fileio* fio)
983 xdr_destroy(fio->xdr);
985 xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
995 int gmx_fio_flush(t_fileio* fio)
1000 ret=gmx_fio_int_flush(fio);
1001 gmx_fio_unlock(fio);
1008 static int gmx_fio_int_fsync(t_fileio *fio)
1016 rc=gmx_fsync(fio->fp);
1018 else if (fio->xdr) /* this should normally not happen */
1020 rc=gmx_fsync((FILE*) fio->xdr->x_private);
1021 /* ^ is this actually OK? */
1028 int gmx_fio_fsync(t_fileio *fio)
1033 rc=gmx_fio_int_fsync(fio);
1034 gmx_fio_unlock(fio);
1041 t_fileio *gmx_fio_all_output_fsync(void)
1046 cur=gmx_fio_get_first();
1049 /* skip debug files (shoud be the only iFTP==efNR) */
1055 /* if any of them fails, return failure code */
1056 int rc=gmx_fio_int_fsync(cur);
1057 if (rc != 0 && !ret)
1062 cur=gmx_fio_get_next(cur);
1065 /* in addition, we force these to be written out too, if they're being
1066 redirected. We don't check for errors because errors most likely mean
1067 that they're not redirected. */
1070 #if (defined(HAVE_FSYNC))
1071 /* again, fahcore defines HAVE_FSYNC and fsync() */
1072 fsync(STDOUT_FILENO);
1073 fsync(STDERR_FILENO);
1080 gmx_off_t gmx_fio_ftell(t_fileio* fio)
1086 ret = gmx_ftell(fio->fp);
1087 gmx_fio_unlock(fio);
1091 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
1098 rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
1105 gmx_fio_unlock(fio);
1109 FILE *gmx_fio_getfp(t_fileio *fio)
1116 gmx_fio_unlock(fio);
1120 XDR *gmx_fio_getxdr(t_fileio* fio)
1127 gmx_fio_unlock(fio);
1132 gmx_bool gmx_fio_getread(t_fileio* fio)
1138 gmx_fio_unlock(fio);
1143 int xtc_seek_frame(t_fileio *fio, int frame, int natoms)
1148 ret=xdr_xtc_seek_frame(frame, fio->fp, fio->xdr, natoms);
1149 gmx_fio_unlock(fio);
1154 int xtc_seek_time(t_fileio *fio, real time, int natoms)
1159 ret=xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms);
1160 gmx_fio_unlock(fio);