brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.7 KiB · 0774b01 Raw
166 lines · cpp
1//===-- lib/runtime/io-error.cpp --------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "flang-rt/runtime/io-error.h"10#include "config.h"11#include "flang-rt/runtime/tools.h"12#include "flang/Runtime/magic-numbers.h"13#include <cerrno>14#include <cstdarg>15#include <cstdio>16#include <cstring>17 18namespace Fortran::runtime::io {19RT_OFFLOAD_API_GROUP_BEGIN20 21void IoErrorHandler::SignalError(int iostatOrErrno, const char *msg, ...) {22  // Note that IOMSG= alone without IOSTAT=/END=/EOR=/ERR= does not suffice23  // for error recovery (see F'2018 subclause 12.11).24  switch (iostatOrErrno) {25  case IostatOk:26    return;27  case IostatEnd:28    if ((flags_ & (hasIoStat | hasEnd)) ||29        ((flags_ & hasErr) && (flags_ & hasRec))) {30      // EOF goes to ERR= when REC= is present31      if (ioStat_ == IostatOk || ioStat_ < IostatEnd) {32        ioStat_ = IostatEnd;33      }34      return;35    }36    break;37  case IostatEor:38    if (flags_ & (hasIoStat | hasEor)) {39      if (ioStat_ == IostatOk || ioStat_ < IostatEor) {40        ioStat_ = IostatEor; // least priority41      }42      return;43    }44    break;45  default:46    if (flags_ & (hasIoStat | hasErr)) {47      if (ioStat_ <= 0) {48        ioStat_ = iostatOrErrno; // priority over END=/EOR=49        if (msg && (flags_ & hasIoMsg)) {50#if !defined(RT_DEVICE_COMPILATION)51          char buffer[256];52          va_list ap;53          va_start(ap, msg);54          std::vsnprintf(buffer, sizeof buffer, msg, ap);55          va_end(ap);56#else57          const char *buffer = "not implemented yet: IOSTAT with varargs";58#endif59          ioMsg_ = SaveDefaultCharacter(60              buffer, Fortran::runtime::strlen(buffer) + 1, *this);61        }62      }63      return;64    }65    break;66  }67  // I/O error not caught!68  if (msg) {69#if !defined(RT_DEVICE_COMPILATION)70    va_list ap;71    va_start(ap, msg);72    CrashArgs(msg, ap);73    va_end(ap);74#else75    Crash("not implemented yet: IOSTAT with varargs");76#endif77  } else if (const char *errstr{IostatErrorString(iostatOrErrno)}) {78    Crash(errstr);79  } else {80#if !defined(RT_DEVICE_COMPILATION)81    Crash("I/O error (errno=%d): %s", iostatOrErrno,82        std::strerror(iostatOrErrno));83#else84    Crash("I/O error (errno=%d)", iostatOrErrno);85#endif86  }87}88 89void IoErrorHandler::SignalError(int iostatOrErrno) {90  SignalError(iostatOrErrno, nullptr);91}92 93void IoErrorHandler::Forward(94    int ioStatOrErrno, const char *msg, std::size_t length) {95  if (ioStatOrErrno != IostatOk) {96    if (msg) {97      SignalError(ioStatOrErrno, "%.*s", static_cast<int>(length), msg);98    } else {99      SignalError(ioStatOrErrno);100    }101  }102}103 104void IoErrorHandler::SignalEnd() { SignalError(IostatEnd); }105 106void IoErrorHandler::SignalEor() { SignalError(IostatEor); }107 108void IoErrorHandler::SignalPendingError() {109  int error{pendingError_};110  pendingError_ = IostatOk;111  SignalError(error);112}113 114void IoErrorHandler::SignalErrno() { SignalError(errno); }115 116bool IoErrorHandler::GetIoMsg(char *buffer, std::size_t bufferLength) {117  const char *msg{ioMsg_.get()};118  if (!msg) {119    msg = IostatErrorString(ioStat_ == IostatOk ? pendingError_ : ioStat_);120  }121  if (msg) {122    ToFortranDefaultCharacter(buffer, bufferLength, msg);123    return true;124  }125 126  // Following code is taken from llvm/lib/Support/Errno.cpp127  // in LLVM v9.0.1 with inadequate modification for Fortran,128  // since rectified.129  bool ok{false};130#if defined(RT_DEVICE_COMPILATION)131  // strerror_r is not available on device.132  msg = "errno description is not available on device";133#elif HAVE_STRERROR_R134  // strerror_r is thread-safe.135#if defined(__GLIBC__) && defined(_GNU_SOURCE)136  // glibc defines its own incompatible version of strerror_r137  // which may not use the buffer supplied.138  msg = ::strerror_r(ioStat_, buffer, bufferLength);139#else140  ok = ::strerror_r(ioStat_, buffer, bufferLength) == 0;141#endif142#elif HAVE_DECL_STRERROR_S // "Windows Secure API"143  ok = ::strerror_s(buffer, bufferLength, ioStat_) == 0;144#else145  // Copy the thread un-safe result of strerror into146  // the buffer as fast as possible to minimize impact147  // of collision of strerror in multiple threads.148  msg = strerror(ioStat_);149#endif150  if (msg) {151    ToFortranDefaultCharacter(buffer, bufferLength, msg);152    return true;153  } else if (ok) {154    std::size_t copied{Fortran::runtime::strlen(buffer)};155    if (copied < bufferLength) {156      runtime::memset(buffer + copied, ' ', bufferLength - copied);157    }158    return true;159  } else {160    return false;161  }162}163 164RT_OFFLOAD_API_GROUP_END165} // namespace Fortran::runtime::io166