a094435c73495cb42ddd81f823155c74d2c6a155
[alexxy/gromacs.git] / src / gromacs / fileio / gmxfio.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
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.
10  *
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.
15  *
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.
20  *
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.
25  *
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.
33  *
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.
36  */
37 #include "gmxpre.h"
38
39 #include "gmxfio.h"
40
41 #include "config.h"
42
43 #include <errno.h>
44 #include <stdio.h>
45 #include <string.h>
46
47 #ifdef HAVE_IO_H
48 #include <io.h>
49 #endif
50 #ifdef HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif
53
54 #include "thread_mpi/threads.h"
55
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"
61
62 #include "gmxfio-impl.h"
63
64 /* This is the new improved and thread safe version of gmxfio. */
65
66
67
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;
71
72
73 /* this mutex locks the open_files structure so that no two threads can
74    modify it.
75
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;
83
84 /******************************************************************
85  *
86  * Internal functions:
87  *
88  ******************************************************************/
89
90 static int gmx_fio_int_flush(t_fileio* fio)
91 {
92     int rc = 0;
93
94     if (fio->fp)
95     {
96         rc = fflush(fio->fp);
97     }
98
99     return rc;
100 }
101
102 /* lock the mutex associated with this fio. This needs to be done for every
103    type of access to the fio's elements. */
104 void gmx_fio_lock(t_fileio *fio)
105 {
106     tMPI_Lock_lock(&(fio->mtx));
107 }
108 /* unlock the mutex associated with this fio.  */
109 void gmx_fio_unlock(t_fileio *fio)
110 {
111     tMPI_Lock_unlock(&(fio->mtx));
112 }
113
114 /* make a dummy head element, assuming we locked everything. */
115 static void gmx_fio_make_dummy(void)
116 {
117     if (!open_files)
118     {
119         snew(open_files, 1);
120         open_files->fp   = NULL;
121         open_files->fn   = NULL;
122         open_files->next = open_files;
123         open_files->prev = open_files;
124         tMPI_Lock_init(&(open_files->mtx));
125     }
126 }
127
128
129
130
131
132
133
134 /***********************************************************************
135  *
136  * FILE LIST OPERATIONS
137  *
138  ***********************************************************************/
139
140
141 /* insert a new t_fileio into the list */
142 static void gmx_fio_insert(t_fileio *fio)
143 {
144     t_fileio *prev;
145     /* first lock the big open_files mutex. */
146     tMPI_Thread_mutex_lock(&open_file_mutex);
147     /* now check whether the dummy element has been allocated,
148        and allocate it if it hasn't */
149     gmx_fio_make_dummy();
150
151     /* and lock the fio we got and the list's head **/
152     gmx_fio_lock(fio);
153     gmx_fio_lock(open_files);
154     prev = open_files->prev;
155     /* lock the element after the current one */
156     if (prev != open_files)
157     {
158         gmx_fio_lock(prev);
159     }
160
161     /* now do the actual insertion: */
162     fio->next        = open_files;
163     open_files->prev = fio;
164     prev->next       = fio;
165     fio->prev        = prev;
166
167     /* now unlock all our locks */
168     if (prev != open_files)
169     {
170         gmx_fio_unlock(prev);
171     }
172     gmx_fio_unlock(open_files);
173     gmx_fio_unlock(fio);
174
175     /* now unlock the big open_files mutex.  */
176     tMPI_Thread_mutex_unlock(&open_file_mutex);
177 }
178
179 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
180    it locked.
181    NOTE: We also assume that the open_file_mutex has been locked */
182 static void gmx_fio_remove(t_fileio *fio)
183 {
184     /* lock prev, because we're changing it */
185     gmx_fio_lock(fio->prev);
186
187     /* now set the prev's pointer */
188     fio->prev->next = fio->next;
189     gmx_fio_unlock(fio->prev);
190
191     /* with the next ptr, we can simply lock while the original was locked */
192     gmx_fio_lock(fio->next);
193     fio->next->prev = fio->prev;
194     gmx_fio_unlock(fio->next);
195
196     /* and make sure we point nowhere in particular */
197     fio->next = fio->prev = fio;
198 }
199
200
201 /* get the first open file, or NULL if there is none.
202    Returns a locked fio. */
203 static t_fileio *gmx_fio_get_first(void)
204 {
205     t_fileio *ret;
206     /* first lock the big open_files mutex and the dummy's mutex */
207
208     /* first lock the big open_files mutex. */
209     tMPI_Thread_mutex_lock(&open_file_mutex);
210     gmx_fio_make_dummy();
211
212     gmx_fio_lock(open_files);
213     ret = open_files->next;
214
215
216     /* check whether there were any to begin with */
217     if (ret == open_files)
218     {
219         /* after this, the open_file pointer should never change */
220         ret = NULL;
221     }
222     else
223     {
224         gmx_fio_lock(open_files->next);
225     }
226     gmx_fio_unlock(open_files);
227
228
229     return ret;
230 }
231
232 /* get the next open file, or NULL if there is none.
233    Unlocks the previous fio and locks the next one. */
234 static t_fileio *gmx_fio_get_next(t_fileio *fio)
235 {
236     t_fileio *ret;
237
238     ret = fio->next;
239     /* check if that was the last one */
240     if (fio->next == open_files)
241     {
242         ret = NULL;
243         tMPI_Thread_mutex_unlock(&open_file_mutex);
244     }
245     else
246     {
247         gmx_fio_lock(ret);
248     }
249     gmx_fio_unlock(fio);
250
251     return ret;
252 }
253
254 /* Stop looping through the open_files.  Unlocks the global lock. */
255 static void gmx_fio_stop_getting_next(t_fileio *fio)
256 {
257     gmx_fio_unlock(fio);
258     tMPI_Thread_mutex_unlock(&open_file_mutex);
259 }
260
261
262
263
264 /*****************************************************************
265  *
266  *                     EXPORTED SECTION
267  *
268  *****************************************************************/
269 t_fileio *gmx_fio_open(const char *fn, const char *mode)
270 {
271     t_fileio *fio = NULL;
272     char      newmode[5];
273     gmx_bool  bRead, bReadWrite;
274
275     /* sanitize the mode string */
276     if (strncmp(mode, "r+", 2) == 0)
277     {
278         strcpy(newmode, "r+");
279     }
280     else if (mode[0] == 'r')
281     {
282         strcpy(newmode, "r");
283     }
284     else if (strncmp(mode, "w+", 2) == 0)
285     {
286         strcpy(newmode, "w+");
287     }
288     else if (mode[0] == 'w')
289     {
290         strcpy(newmode, "w");
291     }
292     else if (strncmp(mode, "a+", 2) == 0)
293     {
294         strcpy(newmode, "a+");
295     }
296     else if (mode[0] == 'a')
297     {
298         strcpy(newmode, "a");
299     }
300     else
301     {
302         gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'", mode);
303     }
304
305     /* Check if it should be opened as a binary file */
306     if (!ftp_is_text(fn2ftp(fn)))
307     {
308         strcat(newmode, "b");
309     }
310
311     snew(fio, 1);
312     tMPI_Lock_init(&(fio->mtx));
313     bRead      = (newmode[0] == 'r' && newmode[1] != '+');
314     bReadWrite = (newmode[1] == '+');
315     fio->fp    = NULL;
316     fio->xdr   = NULL;
317     if (fn)
318     {
319         if (fn2ftp(fn) == efTNG)
320         {
321             gmx_incons("gmx_fio_open may not be used to open TNG files");
322         }
323         fio->iFTP   = fn2ftp(fn);
324         fio->fn     = gmx_strdup(fn);
325
326         fio->fp = gmx_ffopen(fn, newmode);
327         /* If this file type is in the list of XDR files, open it like that */
328         if (ftp_is_xdr(fio->iFTP))
329         {
330             /* determine the XDR direction */
331             if (newmode[0] == 'w' || newmode[0] == 'a')
332             {
333                 fio->xdrmode = XDR_ENCODE;
334             }
335             else
336             {
337                 fio->xdrmode = XDR_DECODE;
338             }
339             snew(fio->xdr, 1);
340             xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
341         }
342
343         /* for appending seek to end of file to make sure ftell gives correct position
344          * important for checkpointing */
345         if (newmode[0] == 'a')
346         {
347             gmx_fseek(fio->fp, 0, SEEK_END);
348         }
349     }
350     fio->bRead             = bRead;
351     fio->bReadWrite        = bReadWrite;
352     fio->bDouble           = (sizeof(real) == sizeof(double));
353
354     /* and now insert this file into the list of open files. */
355     gmx_fio_insert(fio);
356     return fio;
357 }
358
359 static int gmx_fio_close_locked(t_fileio *fio)
360 {
361     int rc = 0;
362
363     if (fio->xdr != NULL)
364     {
365         xdr_destroy(fio->xdr);
366         sfree(fio->xdr);
367     }
368
369     if (fio->fp != NULL)
370     {
371         rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
372
373     }
374
375     return rc;
376 }
377
378 int gmx_fio_close(t_fileio *fio)
379 {
380     int rc = 0;
381
382     /* first lock the big open_files mutex. */
383     /* We don't want two processes operating on the list at the same time */
384     tMPI_Thread_mutex_lock(&open_file_mutex);
385
386     gmx_fio_lock(fio);
387     /* first remove it from the list */
388     gmx_fio_remove(fio);
389     rc = gmx_fio_close_locked(fio);
390     gmx_fio_unlock(fio);
391
392     sfree(fio->fn);
393     sfree(fio);
394
395     tMPI_Thread_mutex_unlock(&open_file_mutex);
396
397     return rc;
398 }
399
400 /* close only fp but keep FIO entry. */
401 int gmx_fio_fp_close(t_fileio *fio)
402 {
403     int rc = 0;
404     gmx_fio_lock(fio);
405     if (fio->xdr == NULL)
406     {
407         rc      = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
408         fio->fp = NULL;
409     }
410     gmx_fio_unlock(fio);
411
412     return rc;
413 }
414
415 FILE * gmx_fio_fopen(const char *fn, const char *mode)
416 {
417     FILE     *ret;
418     t_fileio *fio;
419
420     fio = gmx_fio_open(fn, mode);
421     gmx_fio_lock(fio);
422     ret = fio->fp;
423     gmx_fio_unlock(fio);
424
425     return ret;
426 }
427
428 int gmx_fio_fclose(FILE *fp)
429 {
430     t_fileio *cur;
431     int       rc    = -1;
432
433     cur = gmx_fio_get_first();
434     while (cur)
435     {
436         if (cur->fp == fp)
437         {
438             rc = gmx_fio_close_locked(cur);
439             gmx_fio_remove(cur);
440             gmx_fio_stop_getting_next(cur);
441             sfree(cur->fn);
442             sfree(cur);
443             break;
444         }
445         cur = gmx_fio_get_next(cur);
446     }
447
448     return rc;
449 }
450
451 /* internal variant of get_file_md5 that operates on a locked file */
452 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
453                                     unsigned char digest[])
454 {
455     /*1MB: large size important to catch almost identical files */
456 #define CPT_CHK_LEN  1048576
457     md5_state_t    state;
458     unsigned char *buf;
459     gmx_off_t      read_len;
460     gmx_off_t      seek_offset;
461     int            ret = -1;
462
463     seek_offset = offset - CPT_CHK_LEN;
464     if (seek_offset < 0)
465     {
466         seek_offset = 0;
467     }
468     read_len = offset - seek_offset;
469
470
471     if (fio->fp && fio->bReadWrite)
472     {
473         ret = gmx_fseek(fio->fp, seek_offset, SEEK_SET);
474         if (ret)
475         {
476             gmx_fseek(fio->fp, 0, SEEK_END);
477         }
478     }
479     if (ret) /*either no fp, not readwrite, or fseek not successful */
480     {
481         return -1;
482     }
483
484     snew(buf, CPT_CHK_LEN);
485     /* the read puts the file position back to offset */
486     if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
487     {
488         /* not fatal: md5sum check to prevent overwriting files
489          * works (less safe) without
490          * */
491         if (ferror(fio->fp))
492         {
493             fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
494                     strerror(errno));
495         }
496         else if (feof(fio->fp))
497         {
498             /*
499              * For long runs that checkpoint frequently but write e.g. logs
500              * infrequently we don't want to issue lots of warnings before we
501              * have written anything to the log.
502              */
503             if (0)
504             {
505                 fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
506             }
507         }
508         else
509         {
510             fprintf(
511                     stderr,
512                     "\nTrying to get md5sum: Unknown reason for short read: %s\n",
513                     fio->fn);
514         }
515
516         gmx_fseek(fio->fp, 0, SEEK_END);
517
518         ret = -1;
519     }
520     gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows
521                                         it gives problems otherwise*/
522
523     if (debug)
524     {
525         fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
526     }
527
528     if (!ret)
529     {
530         gmx_md5_init(&state);
531         gmx_md5_append(&state, buf, read_len);
532         gmx_md5_finish(&state, digest);
533         ret = read_len;
534     }
535     sfree(buf);
536     return ret;
537 }
538
539
540 /*
541  * fio: file to compute md5 for
542  * offset: starting pointer of region to use for md5
543  * digest: return array of md5 sum
544  */
545 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
546                          unsigned char digest[])
547 {
548     int ret;
549
550     gmx_fio_lock(fio);
551     ret = gmx_fio_int_get_file_md5(fio, offset, digest);
552     gmx_fio_unlock(fio);
553
554     return ret;
555 }
556
557 /* The fio_mutex should ALWAYS be locked when this function is called */
558 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
559 {
560     /* Flush the file, so we are sure it is written */
561     if (gmx_fio_int_flush(fio))
562     {
563         char buf[STRLEN];
564         sprintf(
565                 buf,
566                 "Cannot write file '%s'; maybe you are out of disk space?",
567                 fio->fn);
568         gmx_file(buf);
569     }
570
571     /* We cannot count on XDR being able to write 64-bit integers,
572        so separate into high/low 32-bit values.
573        In case the filesystem has 128-bit offsets we only care
574        about the first 64 bits - we'll have to fix
575        this when exabyte-size output files are common...
576      */
577     *offset = gmx_ftell(fio->fp);
578
579     return 0;
580 }
581
582 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
583                                       int                  *p_nfiles)
584 {
585     int                   nfiles, nalloc;
586     gmx_file_position_t * outputfiles;
587     t_fileio             *cur;
588
589     nfiles = 0;
590
591     /* pre-allocate 100 files */
592     nalloc = 100;
593     snew(outputfiles, nalloc);
594
595     cur = gmx_fio_get_first();
596     while (cur)
597     {
598         /* Skip the checkpoint files themselves, since they could be open when
599            we call this routine... */
600         if (!cur->bRead && cur->iFTP != efCPT)
601         {
602             /* This is an output file currently open for writing, add it */
603             if (nfiles == nalloc)
604             {
605                 nalloc += 100;
606                 srenew(outputfiles, nalloc);
607             }
608
609             strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
610
611             /* Get the file position */
612             gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
613 #ifndef GMX_FAHCORE
614             outputfiles[nfiles].chksum_size
615                 = gmx_fio_int_get_file_md5(cur,
616                                            outputfiles[nfiles].offset,
617                                            outputfiles[nfiles].chksum);
618 #endif
619             nfiles++;
620         }
621
622         cur = gmx_fio_get_next(cur);
623     }
624     *p_nfiles      = nfiles;
625     *p_outputfiles = outputfiles;
626
627     return 0;
628 }
629
630
631 char *gmx_fio_getname(t_fileio *fio)
632 {
633     char *ret;
634     gmx_fio_lock(fio);
635     ret = fio->fn;
636     gmx_fio_unlock(fio);
637
638     return ret;
639 }
640
641 int gmx_fio_getftp(t_fileio* fio)
642 {
643     int ret;
644
645     gmx_fio_lock(fio);
646     ret = fio->iFTP;
647     gmx_fio_unlock(fio);
648
649     return ret;
650 }
651
652 void gmx_fio_rewind(t_fileio* fio)
653 {
654     gmx_fio_lock(fio);
655
656     if (fio->xdr)
657     {
658         xdr_destroy(fio->xdr);
659         frewind(fio->fp);
660         xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
661     }
662     else
663     {
664         frewind(fio->fp);
665     }
666     gmx_fio_unlock(fio);
667 }
668
669
670 int gmx_fio_flush(t_fileio* fio)
671 {
672     int ret;
673
674     gmx_fio_lock(fio);
675     ret = gmx_fio_int_flush(fio);
676     gmx_fio_unlock(fio);
677
678     return ret;
679 }
680
681
682
683 static int gmx_fio_int_fsync(t_fileio *fio)
684 {
685     int rc    = 0;
686
687     if (fio->fp)
688     {
689         rc = gmx_fsync(fio->fp);
690     }
691
692     return rc;
693 }
694
695
696 int gmx_fio_fsync(t_fileio *fio)
697 {
698     int rc;
699
700     gmx_fio_lock(fio);
701     rc = gmx_fio_int_fsync(fio);
702     gmx_fio_unlock(fio);
703
704     return rc;
705 }
706
707
708
709 t_fileio *gmx_fio_all_output_fsync(void)
710 {
711     t_fileio *ret = NULL;
712     t_fileio *cur;
713
714     cur = gmx_fio_get_first();
715     while (cur)
716     {
717         if (!cur->bRead)
718         {
719             /* if any of them fails, return failure code */
720             int rc = gmx_fio_int_fsync(cur);
721             if (rc != 0 && !ret)
722             {
723                 ret = cur;
724             }
725         }
726         cur = gmx_fio_get_next(cur);
727     }
728
729     /* in addition, we force these to be written out too, if they're being
730        redirected. We don't check for errors because errors most likely mean
731        that they're not redirected. */
732     fflush(stdout);
733     fflush(stderr);
734 #if (defined(HAVE_FSYNC))
735     /* again, fahcore defines HAVE_FSYNC and fsync() */
736     fsync(STDOUT_FILENO);
737     fsync(STDERR_FILENO);
738 #endif
739
740     return ret;
741 }
742
743
744 gmx_off_t gmx_fio_ftell(t_fileio* fio)
745 {
746     gmx_off_t ret = 0;
747
748     gmx_fio_lock(fio);
749     if (fio->fp)
750     {
751         ret = gmx_ftell(fio->fp);
752     }
753     gmx_fio_unlock(fio);
754     return ret;
755 }
756
757 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
758 {
759     int rc;
760
761     gmx_fio_lock(fio);
762     if (fio->fp)
763     {
764         rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
765     }
766     else
767     {
768         gmx_file(fio->fn);
769         rc = -1;
770     }
771     gmx_fio_unlock(fio);
772     return rc;
773 }
774
775 FILE *gmx_fio_getfp(t_fileio *fio)
776 {
777     FILE *ret = NULL;
778
779     gmx_fio_lock(fio);
780     if (fio->fp)
781     {
782         ret = fio->fp;
783     }
784     gmx_fio_unlock(fio);
785     return ret;
786 }
787
788 gmx_bool gmx_fio_getread(t_fileio* fio)
789 {
790     gmx_bool ret;
791
792     gmx_fio_lock(fio);
793     ret = fio->bRead;
794     gmx_fio_unlock(fio);
795
796     return ret;
797 }
798
799 int xtc_seek_time(t_fileio *fio, real time, int natoms, gmx_bool bSeekForwardOnly)
800 {
801     int ret;
802
803     gmx_fio_lock(fio);
804     ret = xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms, bSeekForwardOnly);
805     gmx_fio_unlock(fio);
806
807     return ret;
808 }