Remove unused thole polarization rfac parameter
[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,2016,2017 by the GROMACS development team.
7  * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
8  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9  * and including many others, as listed in the AUTHORS file in the
10  * top-level source directory and at http://www.gromacs.org.
11  *
12  * GROMACS is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public License
14  * as published by the Free Software Foundation; either version 2.1
15  * of the License, or (at your option) any later version.
16  *
17  * GROMACS is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with GROMACS; if not, see
24  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
26  *
27  * If you want to redistribute modifications to GROMACS, please
28  * consider that scientific software is very special. Version
29  * control is crucial - bugs must be traceable. We will be happy to
30  * consider code for inclusion in the official distribution, but
31  * derived work must not be called official GROMACS. Details are found
32  * in the README & COPYING files - if they are missing, get the
33  * official version at http://www.gromacs.org.
34  *
35  * To help us fund GROMACS development, we humbly ask that you cite
36  * the research papers on the package. Check out http://www.gromacs.org.
37  */
38 #include "gmxpre.h"
39
40 #include "gmxfio.h"
41
42 #include "config.h"
43
44 #include <cerrno>
45 #include <cstdio>
46 #include <cstring>
47
48 #include <mutex>
49 #include <vector>
50
51 #if HAVE_IO_H
52 #    include <io.h>
53 #endif
54 #ifdef HAVE_UNISTD_H
55 #    include <unistd.h>
56 #endif
57
58 #include "thread_mpi/threads.h"
59
60 #include "gromacs/fileio/filetypes.h"
61 #include "gromacs/fileio/md5.h"
62 #include "gromacs/utility/fatalerror.h"
63 #include "gromacs/utility/futil.h"
64 #include "gromacs/utility/smalloc.h"
65
66 #include "gmxfio_impl.h"
67
68 /* This is the new improved and thread safe version of gmxfio. */
69
70
71 /* the list of open files is a linked list, with a dummy element at its head;
72        it is initialized when the first file is opened. */
73 // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
74 static t_fileio* open_files = nullptr;
75
76
77 /* this mutex locks the open_files structure so that no two threads can
78    modify it.
79
80    For now, we use this as a coarse grained lock on all file
81    insertion/deletion operations because it makes avoiding deadlocks
82    easier, and adds almost no overhead: the only overhead is during
83    opening and closing of files, or during global operations like
84    iterating along all open files. All these cases should be rare
85    during the simulation. */
86 // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
87 static std::mutex open_file_mutex;
88
89 using Lock = std::lock_guard<std::mutex>;
90
91 /******************************************************************
92  *
93  * Internal functions:
94  *
95  ******************************************************************/
96
97 static int gmx_fio_int_flush(t_fileio* fio)
98 {
99     int rc = 0;
100
101     if (fio->fp)
102     {
103         rc = fflush(fio->fp);
104     }
105
106     return rc;
107 }
108
109 /* lock the mutex associated with this fio. This needs to be done for every
110    type of access to the fio's elements. */
111 void gmx_fio_lock(t_fileio* fio)
112 {
113     tMPI_Lock_lock(&(fio->mtx));
114 }
115 /* unlock the mutex associated with this fio.  */
116 void gmx_fio_unlock(t_fileio* fio)
117 {
118     tMPI_Lock_unlock(&(fio->mtx));
119 }
120
121 /* make a dummy head element, assuming we locked everything. */
122 static void gmx_fio_make_dummy()
123 {
124     if (!open_files)
125     {
126         open_files       = new t_fileio{};
127         open_files->fp   = nullptr;
128         open_files->fn   = nullptr;
129         open_files->next = open_files;
130         open_files->prev = open_files;
131         tMPI_Lock_init(&(open_files->mtx));
132     }
133 }
134
135
136 /***********************************************************************
137  *
138  * FILE LIST OPERATIONS
139  *
140  ***********************************************************************/
141
142
143 /* insert a new t_fileio into the list */
144 static void gmx_fio_insert(t_fileio* fio)
145 {
146     t_fileio* prev;
147     Lock      openFilesLock(open_file_mutex);
148     gmx_fio_make_dummy();
149
150     /* and lock the fio we got and the list's head **/
151     gmx_fio_lock(fio);
152     gmx_fio_lock(open_files);
153     prev = open_files->prev;
154     /* lock the element after the current one */
155     if (prev != open_files)
156     {
157         gmx_fio_lock(prev);
158     }
159
160     /* now do the actual insertion: */
161     fio->next        = open_files;
162     open_files->prev = fio;
163     prev->next       = fio;
164     fio->prev        = prev;
165
166     /* now unlock all our locks */
167     if (prev != open_files)
168     {
169         gmx_fio_unlock(prev);
170     }
171     gmx_fio_unlock(open_files);
172     gmx_fio_unlock(fio);
173 }
174
175 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
176    it locked.
177    NOTE: We also assume that the open_file_mutex has been locked */
178 static void gmx_fio_remove(t_fileio* fio)
179 {
180     /* lock prev, because we're changing it */
181     gmx_fio_lock(fio->prev);
182
183     /* now set the prev's pointer */
184     fio->prev->next = fio->next;
185     gmx_fio_unlock(fio->prev);
186
187     /* with the next ptr, we can simply lock while the original was locked */
188     gmx_fio_lock(fio->next);
189     fio->next->prev = fio->prev;
190     gmx_fio_unlock(fio->next);
191
192     /* and make sure we point nowhere in particular */
193     fio->next = fio->prev = fio;
194 }
195
196
197 /* get the first open file, or NULL if there is none.
198    Returns a locked fio. Assumes open_files_mutex is locked. */
199 static t_fileio* gmx_fio_get_first()
200 {
201     t_fileio* ret;
202
203     gmx_fio_make_dummy();
204
205     gmx_fio_lock(open_files);
206     ret = open_files->next;
207
208
209     /* check whether there were any to begin with */
210     if (ret == open_files)
211     {
212         /* after this, the open_file pointer should never change */
213         ret = nullptr;
214     }
215     else
216     {
217         gmx_fio_lock(open_files->next);
218     }
219     gmx_fio_unlock(open_files);
220
221
222     return ret;
223 }
224
225 /* get the next open file, or NULL if there is none.
226    Unlocks the previous fio and locks the next one.
227    Assumes open_file_mutex is locked. */
228 static t_fileio* gmx_fio_get_next(t_fileio* fio)
229 {
230     t_fileio* ret;
231
232     ret = fio->next;
233     /* check if that was the last one */
234     if (fio->next == open_files)
235     {
236         ret = nullptr;
237     }
238     else
239     {
240         gmx_fio_lock(ret);
241     }
242     gmx_fio_unlock(fio);
243
244     return ret;
245 }
246
247 /* Stop looping through the open_files. Assumes open_file_mutex is locked. */
248 static void gmx_fio_stop_getting_next(t_fileio* fio)
249 {
250     gmx_fio_unlock(fio);
251 }
252
253
254 /*****************************************************************
255  *
256  *                     EXPORTED SECTION
257  *
258  *****************************************************************/
259 t_fileio* gmx_fio_open(const char* fn, const char* mode)
260 {
261     t_fileio* fio = nullptr;
262     char      newmode[5];
263     gmx_bool  bRead, bReadWrite;
264
265     /* sanitize the mode string */
266     if (std::strncmp(mode, "r+", 2) == 0)
267     {
268         std::strcpy(newmode, "r+");
269     }
270     else if (mode[0] == 'r')
271     {
272         std::strcpy(newmode, "r");
273     }
274     else if (strncmp(mode, "w+", 2) == 0)
275     {
276         std::strcpy(newmode, "w+");
277     }
278     else if (mode[0] == 'w')
279     {
280         std::strcpy(newmode, "w");
281     }
282     else if (strncmp(mode, "a+", 2) == 0)
283     {
284         std::strcpy(newmode, "a+");
285     }
286     else if (mode[0] == 'a')
287     {
288         std::strcpy(newmode, "a");
289     }
290     else
291     {
292         gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'", mode);
293     }
294
295     /* Check if it should be opened as a binary file */
296     if (!ftp_is_text(fn2ftp(fn)))
297     {
298         strcat(newmode, "b");
299     }
300
301     fio = new t_fileio{};
302     tMPI_Lock_init(&(fio->mtx));
303     bRead      = (newmode[0] == 'r' && newmode[1] != '+');
304     bReadWrite = (newmode[1] == '+');
305     fio->fp    = nullptr;
306     fio->xdr   = nullptr;
307     if (fn)
308     {
309         if (fn2ftp(fn) == efTNG)
310         {
311             gmx_incons("gmx_fio_open may not be used to open TNG files");
312         }
313         fio->iFTP = fn2ftp(fn);
314         fio->fn   = gmx_strdup(fn);
315
316         fio->fp = gmx_ffopen(fn, newmode);
317         /* If this file type is in the list of XDR files, open it like that */
318         if (ftp_is_xdr(fio->iFTP))
319         {
320             /* determine the XDR direction */
321             if (newmode[0] == 'w' || newmode[0] == 'a')
322             {
323                 fio->xdrmode = XDR_ENCODE;
324             }
325             else
326             {
327                 fio->xdrmode = XDR_DECODE;
328             }
329             snew(fio->xdr, 1);
330             xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
331         }
332
333         /* for appending seek to end of file to make sure ftell gives correct position
334          * important for checkpointing */
335         if (newmode[0] == 'a')
336         {
337             gmx_fseek(fio->fp, 0, SEEK_END);
338         }
339     }
340     else
341     {
342         gmx_fatal(FARGS, "Cannot open file with NULL filename string");
343     }
344
345     fio->bRead      = bRead;
346     fio->bReadWrite = bReadWrite;
347     fio->bDouble    = (sizeof(real) == sizeof(double));
348
349     /* and now insert this file into the list of open files. */
350     gmx_fio_insert(fio);
351     return fio;
352 }
353
354 static int gmx_fio_close_locked(t_fileio* fio)
355 {
356     int rc = 0;
357
358     if (fio->xdr != nullptr)
359     {
360         xdr_destroy(fio->xdr);
361         sfree(fio->xdr);
362     }
363
364     if (fio->fp != nullptr)
365     {
366         rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
367     }
368
369     return rc;
370 }
371
372 int gmx_fio_close(t_fileio* fio)
373 {
374     int rc = 0;
375
376     Lock openFilesLock(open_file_mutex);
377
378     gmx_fio_lock(fio);
379     /* first remove it from the list */
380     gmx_fio_remove(fio);
381     rc = gmx_fio_close_locked(fio);
382     gmx_fio_unlock(fio);
383
384     sfree(fio->fn);
385     delete fio;
386
387     return rc;
388 }
389
390 /* close only fp but keep FIO entry. */
391 int gmx_fio_fp_close(t_fileio* fio)
392 {
393     int rc = 0;
394     gmx_fio_lock(fio);
395     if (fio->xdr == nullptr)
396     {
397         rc      = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
398         fio->fp = nullptr;
399     }
400     gmx_fio_unlock(fio);
401
402     return rc;
403 }
404
405 FILE* gmx_fio_fopen(const char* fn, const char* mode)
406 {
407     FILE*     ret;
408     t_fileio* fio;
409
410     fio = gmx_fio_open(fn, mode);
411     gmx_fio_lock(fio);
412     ret = fio->fp;
413     gmx_fio_unlock(fio);
414
415     return ret;
416 }
417
418 int gmx_fio_fclose(FILE* fp)
419 {
420     t_fileio* cur;
421     int       rc = -1;
422
423     Lock openFilesLock(open_file_mutex);
424     cur = gmx_fio_get_first();
425     while (cur)
426     {
427         if (cur->fp == fp)
428         {
429             rc = gmx_fio_close_locked(cur);
430             gmx_fio_remove(cur);
431             gmx_fio_stop_getting_next(cur);
432             sfree(cur->fn);
433             delete cur;
434             break;
435         }
436         cur = gmx_fio_get_next(cur);
437     }
438
439     return rc;
440 }
441
442 //! Helper struct for returning the MD5 checksum and the amount of the file that contributed to it.
443 struct MD5Checksum
444 {
445     //! Checksum md5 digest.
446     std::array<unsigned char, 16> checksum;
447     //! The length of the file that contributed to the digest.
448     gmx_off_t readLength;
449 };
450
451 /*! \brief Internal variant of get_file_md5 that operates on a locked
452  * file.
453  *
454  * \return -1 any time a checksum cannot be computed, otherwise the
455  *            length of the data from which the checksum was computed. */
456 static int gmx_fio_int_get_file_md5(t_fileio* fio, gmx_off_t offset, std::array<unsigned char, 16>* checksum)
457 {
458     /*1MB: large size important to catch almost identical files */
459     constexpr size_t maximumChecksumInputSize = 1048576;
460     md5_state_t      state;
461     gmx_off_t        readLength;
462     gmx_off_t        seekOffset;
463
464     seekOffset = offset - maximumChecksumInputSize;
465     if (seekOffset < 0)
466     {
467         seekOffset = 0;
468     }
469     readLength = offset - seekOffset;
470
471     if (!fio->fp)
472     {
473         // It's not an error if the file isn't open.
474         return -1;
475     }
476     if (!fio->bReadWrite)
477     {
478         // It's not an error if the file is open in the wrong mode.
479         //
480         // TODO It is unclear why this check exists. The bReadWrite
481         // flag is true when the file-opening mode included "+" but we
482         // only need read and seek to be able to compute the
483         // md5sum. Other requirements (e.g. that we can truncate when
484         // doing an appending restart) should be expressed in a
485         // different way, but it is unclear whether that is part of
486         // the logic here.
487         return -1;
488     }
489
490     if (gmx_fseek(fio->fp, seekOffset, SEEK_SET))
491     {
492         // It's not an error if file seeking fails. (But it could be
493         // an issue when moving a checkpoint from one platform to
494         // another, when they differ in their support for seeking, and
495         // so can't agree on a checksum for appending).
496         gmx_fseek(fio->fp, 0, SEEK_END);
497         return -1;
498     }
499
500     std::vector<unsigned char> buf(maximumChecksumInputSize);
501     // The fread puts the file position back to offset.
502     if (static_cast<gmx_off_t>(fread(buf.data(), 1, readLength, fio->fp)) != readLength)
503     {
504         // Read an unexpected length. This is not a fatal error; the
505         // md5sum check to prevent overwriting files is not vital.
506         if (ferror(fio->fp))
507         {
508             fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn, strerror(errno));
509         }
510         else if (!feof(fio->fp))
511         {
512             fprintf(stderr, "\nTrying to get md5sum: Unknown reason for short read: %s\n", fio->fn);
513         }
514
515         gmx_fseek(fio->fp, 0, SEEK_END);
516         return -1;
517     }
518     // Return the file position to the end of the file.
519     gmx_fseek(fio->fp, 0, SEEK_END);
520
521     if (debug)
522     {
523         fprintf(debug, "chksum %s readlen %ld\n", fio->fn, static_cast<long int>(readLength));
524     }
525
526     gmx_md5_init(&state);
527     gmx_md5_append(&state, buf.data(), readLength);
528     *checksum = gmx_md5_finish(&state);
529     return readLength;
530 }
531
532
533 /*
534  * fio: file to compute md5 for
535  * offset: starting pointer of region to use for md5
536  * digest: return array of md5 sum
537  */
538 int gmx_fio_get_file_md5(t_fileio* fio, gmx_off_t offset, std::array<unsigned char, 16>* checksum)
539 {
540     int ret;
541
542     gmx_fio_lock(fio);
543     ret = gmx_fio_int_get_file_md5(fio, offset, checksum);
544     gmx_fio_unlock(fio);
545
546     return ret;
547 }
548
549 /* The fio_mutex should ALWAYS be locked when this function is called */
550 static int gmx_fio_int_get_file_position(t_fileio* fio, gmx_off_t* offset)
551 {
552     /* Flush the file, so we are sure it is written */
553     if (gmx_fio_int_flush(fio))
554     {
555         char buf[STRLEN];
556         sprintf(buf, "Cannot write file '%s'; maybe you are out of disk space?", fio->fn);
557         gmx_file(buf);
558     }
559
560     /* We cannot count on XDR being able to write 64-bit integers,
561        so separate into high/low 32-bit values.
562        In case the filesystem has 128-bit offsets we only care
563        about the first 64 bits - we'll have to fix
564        this when exabyte-size output files are common...
565      */
566     *offset = gmx_ftell(fio->fp);
567
568     return 0;
569 }
570
571 std::vector<gmx_file_position_t> gmx_fio_get_output_file_positions()
572 {
573     std::vector<gmx_file_position_t> outputfiles;
574     t_fileio*                        cur;
575
576     Lock openFilesLock(open_file_mutex);
577     cur = gmx_fio_get_first();
578     while (cur)
579     {
580         /* Skip the checkpoint files themselves, since they could be open when
581            we call this routine... */
582         if (!cur->bRead && cur->iFTP != efCPT)
583         {
584             outputfiles.emplace_back();
585
586             std::strncpy(outputfiles.back().filename, cur->fn, STRLEN - 1);
587
588             /* Get the file position */
589             gmx_fio_int_get_file_position(cur, &outputfiles.back().offset);
590             if (!GMX_FAHCORE)
591             {
592                 outputfiles.back().checksumSize = gmx_fio_int_get_file_md5(
593                         cur, outputfiles.back().offset, &outputfiles.back().checksum);
594             }
595         }
596
597         cur = gmx_fio_get_next(cur);
598     }
599
600     return outputfiles;
601 }
602
603
604 char* gmx_fio_getname(t_fileio* fio)
605 {
606     char* ret;
607     gmx_fio_lock(fio);
608     ret = fio->fn;
609     gmx_fio_unlock(fio);
610
611     return ret;
612 }
613
614 int gmx_fio_getftp(t_fileio* fio)
615 {
616     int ret;
617
618     gmx_fio_lock(fio);
619     ret = fio->iFTP;
620     gmx_fio_unlock(fio);
621
622     return ret;
623 }
624
625 void gmx_fio_rewind(t_fileio* fio)
626 {
627     gmx_fio_lock(fio);
628
629     if (fio->xdr)
630     {
631         xdr_destroy(fio->xdr);
632         frewind(fio->fp);
633         xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
634     }
635     else
636     {
637         frewind(fio->fp);
638     }
639     gmx_fio_unlock(fio);
640 }
641
642
643 int gmx_fio_flush(t_fileio* fio)
644 {
645     int ret;
646
647     gmx_fio_lock(fio);
648     ret = gmx_fio_int_flush(fio);
649     gmx_fio_unlock(fio);
650
651     return ret;
652 }
653
654
655 static int gmx_fio_int_fsync(t_fileio* fio)
656 {
657     int rc = 0;
658
659     if (fio->fp)
660     {
661         rc = gmx_fsync(fio->fp);
662     }
663     return rc;
664 }
665
666
667 int gmx_fio_fsync(t_fileio* fio)
668 {
669     int rc;
670
671     gmx_fio_lock(fio);
672     rc = gmx_fio_int_fsync(fio);
673     gmx_fio_unlock(fio);
674
675     return rc;
676 }
677
678
679 t_fileio* gmx_fio_all_output_fsync()
680 {
681     t_fileio* ret = nullptr;
682     t_fileio* cur;
683
684     Lock openFilesLock(open_file_mutex);
685     cur = gmx_fio_get_first();
686     while (cur)
687     {
688         if (!cur->bRead)
689         {
690             /* if any of them fails, return failure code */
691             int rc = gmx_fio_int_fsync(cur);
692             if (rc != 0 && !ret)
693             {
694                 ret = cur;
695             }
696         }
697         cur = gmx_fio_get_next(cur);
698     }
699
700     /* in addition, we force these to be written out too, if they're being
701        redirected. We don't check for errors because errors most likely mean
702        that they're not redirected. */
703     fflush(stdout);
704     fflush(stderr);
705 #if HAVE_FSYNC
706     /* again, fahcore defines HAVE_FSYNC and fsync() */
707     fsync(STDOUT_FILENO);
708     fsync(STDERR_FILENO);
709 #endif
710
711     return ret;
712 }
713
714
715 gmx_off_t gmx_fio_ftell(t_fileio* fio)
716 {
717     gmx_off_t ret = 0;
718
719     gmx_fio_lock(fio);
720     if (fio->fp)
721     {
722         ret = gmx_ftell(fio->fp);
723     }
724     gmx_fio_unlock(fio);
725     return ret;
726 }
727
728 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
729 {
730     int rc;
731
732     gmx_fio_lock(fio);
733     if (fio->fp)
734     {
735         rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
736     }
737     else
738     {
739         gmx_file(fio->fn);
740     }
741     gmx_fio_unlock(fio);
742     return rc;
743 }
744
745 FILE* gmx_fio_getfp(t_fileio* fio)
746 {
747     FILE* ret = nullptr;
748
749     gmx_fio_lock(fio);
750     if (fio->fp)
751     {
752         ret = fio->fp;
753     }
754     gmx_fio_unlock(fio);
755     return ret;
756 }
757
758 gmx_bool gmx_fio_getread(t_fileio* fio)
759 {
760     gmx_bool ret;
761
762     gmx_fio_lock(fio);
763     ret = fio->bRead;
764     gmx_fio_unlock(fio);
765
766     return ret;
767 }
768
769 int xtc_seek_time(t_fileio* fio, real time, int natoms, gmx_bool bSeekForwardOnly)
770 {
771     int ret;
772
773     gmx_fio_lock(fio);
774     ret = xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms, bSeekForwardOnly);
775     gmx_fio_unlock(fio);
776
777     return ret;
778 }