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 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 #if (defined( _WIN32 ) || defined( _WIN64 ) )
188 /* windows doesn't do standard C */
189 #define snprintf sprintf_s
191 snprintf(buf
, GMX_FIO_BUFLEN
, " ; %s %s",
192 fio
->comment
? fio
->comment
: "", desc
);
198 /* check the number of items given against the type */
199 void gmx_fio_check_nitem(t_fileio
*fio
, int eio
, int nitem
, const char *file
,
202 if ((nitem
!= 1) && !((eio
== eioNRVEC
) || (eio
== eioNUCHAR
)))
204 "nitem (%d) may differ from 1 only for %s or %s, not for %s"
205 "(%s, %d)",nitem
,eioNames
[eioNUCHAR
],eioNames
[eioNRVEC
],
206 eioNames
[eio
],file
,line
);
210 /* output a data type error. */
211 void gmx_fio_fe(t_fileio
*fio
, int eio
, const char *desc
,
212 const char *srcfile
, int line
)
215 gmx_fatal(FARGS
, "Trying to %s %s type %d (%s), src %s, line %d",
216 fio
->bRead
? "read" : "write",desc
,eio
,
217 ((eio
>= 0) && (eio
< eioNR
)) ? eioNames
[eio
] : "unknown",
222 /* set the reader/writer functions based on the file type */
223 static void gmx_fio_set_iotype(t_fileio
*fio
)
225 if (in_ftpset(fio
->iFTP
, asize(ftpXDR
), ftpXDR
))
228 fio
->iotp
=&xdr_iotype
;
230 gmx_fatal(FARGS
,"Sorry, no XDR");
233 else if (in_ftpset(fio
->iFTP
, asize(ftpASC
), ftpASC
))
235 fio
->iotp
=&asc_iotype
;
237 else if (in_ftpset(fio
->iFTP
, asize(ftpBIN
), ftpBIN
))
239 fio
->iotp
=&bin_iotype
;
242 else if (in_ftpset(fio
->iFTP
,asize(ftpXML
),ftpXML
))
244 fio
->iotp
=&dummy_iotype
;
248 fio
->iotp
=&dummy_iotype
;
252 /* lock the mutex associated with this fio. This needs to be done for every
253 type of access to the fio's elements. */
254 void gmx_fio_lock(t_fileio
*fio
)
257 tMPI_Spinlock_lock(&(fio
->mtx
));
260 /* unlock the mutex associated with this fio. */
261 void gmx_fio_unlock(t_fileio
*fio
)
264 tMPI_Spinlock_unlock(&(fio
->mtx
));
268 /* make a dummy head element, assuming we locked everything. */
269 static void gmx_fio_make_dummy(void)
276 open_files
->next
=open_files
;
277 open_files
->prev
=open_files
;
279 tMPI_Spinlock_init(&(open_files
->mtx
));
290 /***********************************************************************
292 * FILE LIST OPERATIONS
294 ***********************************************************************/
297 /* insert a new t_fileio into the list */
298 static void gmx_fio_insert(t_fileio
*fio
)
302 /* first lock the big open_files mutex. */
303 tMPI_Thread_mutex_lock(&open_file_mutex
);
305 /* now check whether the dummy element has been allocated,
306 and allocate it if it hasn't */
307 gmx_fio_make_dummy();
309 /* and lock the fio we got and the list's head **/
311 gmx_fio_lock(open_files
);
312 prev
=open_files
->prev
;
313 /* lock the element after the current one */
314 if (prev
!= open_files
)
319 /* now do the actual insertion: */
320 fio
->next
=open_files
;
321 open_files
->prev
=fio
;
325 /* now unlock all our locks */
326 if (prev
!= open_files
)
328 gmx_fio_unlock(prev
);
330 gmx_fio_unlock(open_files
);
334 /* now unlock the big open_files mutex. */
335 tMPI_Thread_mutex_unlock(&open_file_mutex
);
339 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
341 static void gmx_fio_remove(t_fileio
*fio
, bool global_lock
)
346 /* first lock the big open_files mutex. */
347 /* We don't want two processes operating on this list at the same time */
349 tMPI_Thread_mutex_lock(&open_file_mutex
);
352 /* lock prev, because we're changing it */
353 gmx_fio_lock(fio
->prev
);
355 /* now set the prev's pointer */
356 fio
->prev
->next
=fio
->next
;
357 gmx_fio_unlock(fio
->prev
);
359 /* with the next ptr, we can simply lock while the original was locked */
360 gmx_fio_lock(fio
->next
);
361 fio
->next
->prev
=fio
->prev
;
362 gmx_fio_unlock(fio
->next
);
364 /* and make sure we point nowhere in particular */
365 fio
->next
=fio
->prev
=fio
;
368 /* now unlock the big open_files mutex. */
370 tMPI_Thread_mutex_unlock(&open_file_mutex
);
376 /* get the first open file, or NULL if there is none.
377 Returns a locked fio. */
378 static t_fileio
*gmx_fio_get_first(void)
381 /* first lock the big open_files mutex and the dummy's mutex */
384 /* first lock the big open_files mutex. */
385 tMPI_Thread_mutex_lock(&open_file_mutex
);
387 gmx_fio_make_dummy();
389 gmx_fio_lock(open_files
);
390 ret
=open_files
->next
;
393 /* check whether there were any to begin with */
396 /* after this, the open_file pointer should never change */
401 gmx_fio_lock(open_files
->next
);
403 gmx_fio_unlock(open_files
);
409 /* get the next open file, or NULL if there is none.
410 Unlocks the previous fio and locks the next one. */
411 static t_fileio
*gmx_fio_get_next(t_fileio
*fio
)
416 /* check if that was the last one */
417 if (fio
->next
==open_files
)
421 tMPI_Thread_mutex_unlock(&open_file_mutex
);
433 /* Stop looping through the open_files. Unlocks the global lock. */
434 static void gmx_fio_stop_getting_next(t_fileio
*fio
)
438 tMPI_Thread_mutex_unlock(&open_file_mutex
);
445 /*****************************************************************
449 *****************************************************************/
450 t_fileio
*gmx_fio_open(const char *fn
, const char *mode
)
452 t_fileio
*fio
= NULL
;
455 bool bRead
, bReadWrite
;
458 if (fn2ftp(fn
) == efTPA
)
460 strcpy(newmode
, mode
);
464 /* sanitize the mode string */
465 if (strncmp(mode
, "r+", 2) == 0)
467 strcpy(newmode
, "r+");
469 else if (mode
[0] == 'r')
471 strcpy(newmode
, "r");
473 else if (strncmp(mode
, "w+", 2) == 0)
475 strcpy(newmode
, "w+");
477 else if (mode
[0] == 'w')
479 strcpy(newmode
, "w");
481 else if (strncmp(mode
, "a+", 2) == 0)
483 strcpy(newmode
, "a+");
485 else if (mode
[0] == 'a')
487 strcpy(newmode
, "a");
491 gmx_fatal(FARGS
, "DEATH HORROR in gmx_fio_open, mode is '%s'",mode
);
495 /* Check if it should be opened as a binary file */
496 if (strncmp(ftp2ftype(fn2ftp(fn
)),"ASCII",5))
498 /* Not ascii, add b to file mode */
499 if ((strchr(newmode
,'b')==NULL
) && (strchr(newmode
,'B')==NULL
))
507 tMPI_Spinlock_init(&(fio
->mtx
));
509 bRead
= (newmode
[0]=='r' && newmode
[1]!='+');
510 bReadWrite
= (newmode
[1]=='+');
515 fio
->iFTP
= fn2ftp(fn
);
516 fio
->fn
= strdup(fn
);
519 /* If this file type is in the list of XDR files, open it like that */
520 if (in_ftpset(fio
->iFTP
,asize(ftpXDR
),ftpXDR
))
522 /* First check whether we have to make a backup,
523 * only for writing, not for read or append.
528 /* only make backups for normal gromacs */
534 /* Check whether file exists */
541 fio
->fp
= ffopen(fn
,newmode
);
543 /* determine the XDR direction */
544 if (newmode
[0] == 'w' || newmode
[0]=='a')
546 fio
->xdrmode
=XDR_ENCODE
;
550 fio
->xdrmode
=XDR_DECODE
;
554 xdrstdio_create(fio
->xdr
, fio
->fp
, fio
->xdrmode
);
558 /* If it is not, open it as a regular file */
559 fio
->fp
= ffopen(fn
,newmode
);
564 /* Use stdin/stdout for I/O */
566 fio
->fp
= bRead
? stdin
: stdout
;
567 fio
->fn
= strdup("STDIO");
571 fio
->bReadWrite
= bReadWrite
;
572 fio
->bDouble
= (sizeof(real
) == sizeof(double));
575 fio
->bLargerThan_off_t
= FALSE
;
577 /* set the reader/writer functions */
578 gmx_fio_set_iotype(fio
);
580 /* and now insert this file into the list of open files. */
585 static int gmx_fio_close_locked(t_fileio
*fio
)
591 gmx_fatal(FARGS
,"File %s closed twice!\n", fio
->fn
);
594 if (in_ftpset(fio
->iFTP
, asize(ftpXDR
), ftpXDR
))
596 xdr_destroy(fio
->xdr
);
600 /* Don't close stdin and stdout! */
601 if (!fio
->bStdio
&& fio
->fp
!=NULL
)
602 rc
= ffclose(fio
->fp
); /* fclose returns 0 if happy */
609 int gmx_fio_close(t_fileio
*fio
)
614 /* first remove it from the list */
615 gmx_fio_remove(fio
, TRUE
);
616 rc
=gmx_fio_close_locked(fio
);
624 /* close only fp but keep FIO entry. */
625 int gmx_fio_fp_close(t_fileio
*fio
)
629 if (!in_ftpset(fio
->iFTP
,asize(ftpXDR
),ftpXDR
) && !fio
->bStdio
)
631 rc
= ffclose(fio
->fp
); /* fclose returns 0 if happy */
639 FILE * gmx_fio_fopen(const char *fn
, const char *mode
)
644 fio
= gmx_fio_open(fn
, mode
);
652 int gmx_fio_fclose(FILE *fp
)
655 t_fileio
*found
=NULL
;
658 cur
=gmx_fio_get_first();
663 rc
=gmx_fio_close_locked(cur
);
664 gmx_fio_remove(cur
,FALSE
);
665 gmx_fio_stop_getting_next(cur
);
668 cur
=gmx_fio_get_next(cur
);
674 /* internal variant of get_file_md5 that operates on a locked file */
675 static int gmx_fio_int_get_file_md5(t_fileio
*fio
, gmx_off_t offset
,
676 unsigned char digest
[])
678 /*1MB: large size important to catch almost identical files */
679 #define CPT_CHK_LEN 1048576
681 unsigned char buf
[CPT_CHK_LEN
];
683 gmx_off_t seek_offset
;
686 seek_offset
= offset
- CPT_CHK_LEN
;
691 read_len
= offset
- seek_offset
;
694 if (fio
->fp
&& fio
->bReadWrite
)
696 ret
=gmx_fseek(fio
->fp
, seek_offset
, SEEK_SET
);
699 gmx_fseek(fio
->fp
, 0, SEEK_END
);
702 if (ret
) /*either no fp, not readwrite, or fseek not successful */
707 /* the read puts the file position back to offset */
708 if ((gmx_off_t
)fread(buf
, 1, read_len
, fio
->fp
) != read_len
)
710 /* not fatal: md5sum check to prevent overwriting files
711 * works (less safe) without
715 fprintf(stderr
, "\nTrying to get md5sum: %s: %s\n", fio
->fn
,
718 else if (feof(fio
->fp
))
720 fprintf(stderr
, "\nTrying to get md5sum: EOF: %s\n", fio
->fn
);
726 "\nTrying to get md5sum: Unknown reason for short read: %s\n",
730 gmx_fseek(fio
->fp
, 0, SEEK_END
);
734 gmx_fseek(fio
->fp
, 0, SEEK_END
); /*is already at end, but under windows
735 it gives problems otherwise*/
739 fprintf(debug
, "chksum %s readlen %ld\n", fio
->fn
, (long int)read_len
);
745 md5_append(&state
, buf
, read_len
);
746 md5_finish(&state
, digest
);
757 * fio: file to compute md5 for
758 * offset: starting pointer of region to use for md5
759 * digest: return array of md5 sum
761 int gmx_fio_get_file_md5(t_fileio
*fio
, gmx_off_t offset
,
762 unsigned char digest
[])
767 ret
=gmx_fio_int_get_file_md5(fio
, offset
, digest
);
773 /* The fio_mutex should ALWAYS be locked when this function is called */
774 static int gmx_fio_int_get_file_position(t_fileio
*fio
, gmx_off_t
*offset
)
778 /* Flush the file, so we are sure it is written */
779 if (gmx_fio_int_flush(fio
))
784 "Cannot write file '%s'; maybe you are out of disk space or quota?",
789 /* We cannot count on XDR being able to write 64-bit integers,
790 so separate into high/low 32-bit values.
791 In case the filesystem has 128-bit offsets we only care
792 about the first 64 bits - we'll have to fix
793 this when exabyte-size output files are common...
795 *offset
=gmx_ftell(fio
->fp
);
800 int gmx_fio_check_file_position(t_fileio
*fio
)
802 /* If gmx_off_t is 4 bytes we can not store file offset > 2 GB.
803 * If we do not have ftello, we will play it safe.
805 #if (SIZEOF_GMX_OFF_T == 4 || !defined HAVE_FSEEKO)
809 gmx_fio_int_get_file_position(fio
,&offset
);
810 /* We have a 4 byte offset,
811 * make sure that we will detect out of range for all possible cases.
813 if (offset
< 0 || offset
> 2147483647)
815 fio
->bLargerThan_off_t
= TRUE
;
823 int gmx_fio_get_output_file_positions(gmx_file_position_t
**p_outputfiles
,
826 int i
, nfiles
, rc
, nalloc
;
829 gmx_file_position_t
* outputfiles
;
835 /* pre-allocate 100 files */
837 snew(outputfiles
,nalloc
);
839 cur
=gmx_fio_get_first();
842 /* Skip the checkpoint files themselves, since they could be open when
843 we call this routine... */
844 /* also skip debug files (shoud be the only iFTP==efNR) */
848 cur
->iFTP
!= efCPT
&&
852 /* This is an output file currently open for writing, add it */
853 if (nfiles
== nalloc
)
856 srenew(outputfiles
,nalloc
);
859 strncpy(outputfiles
[nfiles
].filename
, cur
->fn
, STRLEN
- 1);
861 /* Get the file position */
862 if (cur
->bLargerThan_off_t
)
864 /* -1 signals out of range */
865 outputfiles
[nfiles
].offset
= -1;
866 outputfiles
[nfiles
].chksum_size
= -1;
870 gmx_fio_int_get_file_position(cur
, &outputfiles
[nfiles
].offset
);
872 outputfiles
[nfiles
].chksum_size
873 = gmx_fio_int_get_file_md5(cur
,
874 outputfiles
[nfiles
].offset
,
875 outputfiles
[nfiles
].chksum
);
882 cur
=gmx_fio_get_next(cur
);
885 *p_outputfiles
= outputfiles
;
891 void gmx_fio_checktype(t_fileio
*fio
)
893 if (in_ftpset(fio
->iFTP
, asize(ftpXDR
), ftpXDR
))
897 else if (in_ftpset(fio
->iFTP
, asize(ftpASC
), ftpASC
))
901 else if (in_ftpset(fio
->iFTP
, asize(ftpBIN
), ftpBIN
))
906 else if (in_ftpset(fio
->iFTP
,asize(ftpXML
),ftpXML
))
912 gmx_fatal(FARGS
, "Can not read/write topologies to file type %s",
918 void gmx_fio_setprecision(t_fileio
*fio
, bool bDouble
)
921 fio
->bDouble
= bDouble
;
925 bool gmx_fio_getdebug(t_fileio
*fio
)
936 void gmx_fio_setdebug(t_fileio
*fio
, bool bDebug
)
939 fio
->bDebug
= bDebug
;
943 char *gmx_fio_getname(t_fileio
*fio
)
953 int gmx_fio_getftp(t_fileio
* fio
)
964 void gmx_fio_rewind(t_fileio
* fio
)
970 xdr_destroy(fio
->xdr
);
972 xdrstdio_create(fio
->xdr
, fio
->fp
, fio
->xdrmode
);
982 int gmx_fio_flush(t_fileio
* fio
)
987 ret
=gmx_fio_int_flush(fio
);
995 static int gmx_fio_int_fsync(t_fileio
*fio
)
1003 rc
=gmx_fsync(fio
->fp
);
1005 else if (fio
->xdr
) /* this should normally not happen */
1007 rc
=gmx_fsync((FILE*) fio
->xdr
->x_private
);
1008 /* ^ is this actually OK? */
1015 int gmx_fio_fsync(t_fileio
*fio
)
1020 rc
=gmx_fio_int_fsync(fio
);
1021 gmx_fio_unlock(fio
);
1028 t_fileio
*gmx_fio_all_output_fsync(void)
1033 cur
=gmx_fio_get_first();
1036 /* skip debug files (shoud be the only iFTP==efNR) */
1042 /* if any of them fails, return failure code */
1043 int rc
=gmx_fio_int_fsync(cur
);
1044 if (rc
!= 0 && !ret
)
1049 cur
=gmx_fio_get_next(cur
);
1052 /* in addition, we force these to be written out too, if they're being
1053 redirected. We don't check for errors because errors most likely mean
1054 that they're not redirected. */
1057 #if (defined(HAVE_FSYNC))
1058 /* again, fahcore defines HAVE_FSYNC and fsync() */
1059 fsync(STDOUT_FILENO
);
1060 fsync(STDERR_FILENO
);
1067 gmx_off_t
gmx_fio_ftell(t_fileio
* fio
)
1073 ret
= gmx_ftell(fio
->fp
);
1074 gmx_fio_unlock(fio
);
1078 int gmx_fio_seek(t_fileio
* fio
, gmx_off_t fpos
)
1085 gmx_fseek(fio
->fp
, fpos
, SEEK_SET
);
1092 gmx_fio_unlock(fio
);
1096 FILE *gmx_fio_getfp(t_fileio
*fio
)
1103 gmx_fio_unlock(fio
);
1107 XDR
*gmx_fio_getxdr(t_fileio
* fio
)
1114 gmx_fio_unlock(fio
);
1119 bool gmx_fio_getread(t_fileio
* fio
)
1125 gmx_fio_unlock(fio
);
1130 int xtc_seek_frame(t_fileio
*fio
, int frame
, int natoms
)
1135 ret
=xdr_xtc_seek_frame(frame
, fio
->fp
, fio
->xdr
, natoms
);
1136 gmx_fio_unlock(fio
);
1141 int xtc_seek_time(t_fileio
*fio
, real time
, int natoms
)
1146 ret
=xdr_xtc_seek_time(time
, fio
->fp
, fio
->xdr
, natoms
);
1147 gmx_fio_unlock(fio
);