COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) {
  FILE *f;
  int fd;
#ifdef COMPILER_RT_HAS_FCNTL_LCK
  struct flock s_flock;

  s_flock.l_whence = SEEK_SET;
  s_flock.l_start = 0;
  s_flock.l_len = 0; /* Until EOF.  */
  s_flock.l_pid = getpid();

  s_flock.l_type = F_WRLCK;
  fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
  if (fd < 0)
    return NULL;

  while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
    if (errno != EINTR) {
      if (errno == ENOLCK) {
        PROF_WARN("Data may be corrupted during profile merging : %s\n",
                  "Fail to obtain file lock due to system limit.");
      }
      break;
    }
  }

  f = fdopen(fd, "r+b");
#elif defined(_WIN32)
  // FIXME: Use the wide variants to handle Unicode filenames.
  HANDLE h = CreateFileA(ProfileName, GENERIC_READ | GENERIC_WRITE, 0, 0,
                         OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  if (h == INVALID_HANDLE_VALUE)
    return NULL;

  fd = _open_osfhandle((intptr_t)h, 0);
  if (fd == -1) {
    CloseHandle(h);
    return NULL;
  }

  f = _fdopen(fd, "r+b");
  if (f == 0) {
    CloseHandle(h);
    return NULL;
  }
#else
  /* Worst case no locking applied.  */
  PROF_WARN("Concurrent file access is not supported : %s\n",
            "lack file locking");
  fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
  if (fd < 0)
    return NULL;
  f = fdopen(fd, "r+b");
#endif

  return f;
}
/* Parses the pattern string \p FilenamePat and stores the result to
 * lprofcurFilename structure. */
static int parseFilenamePattern(const char *FilenamePat) {
    int NumPids = 0, NumHosts = 0, I;
    char *PidChars = &lprofCurFilename.PidChars[0];
    char *Hostname = &lprofCurFilename.Hostname[0];
    int MergingEnabled = 0;

    lprofCurFilename.FilenamePat = FilenamePat;
    /* Check the filename for "%p", which indicates a pid-substitution. */
    for (I = 0; FilenamePat[I]; ++I)
        if (FilenamePat[I] == '%') {
            if (FilenamePat[++I] == 'p') {
                if (!NumPids++) {
                    if (snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()) <= 0) {
                        PROF_WARN(
                            "Unable to parse filename pattern %s. Using the default name.",
                            FilenamePat);
                        return -1;
                    }
                }
            } else if (FilenamePat[I] == 'h') {
                if (!NumHosts++)
                    if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) {
                        PROF_WARN(
                            "Unable to parse filename pattern %s. Using the default name.",
                            FilenamePat);
                        return -1;
                    }
            } else if (containsMergeSpecifier(FilenamePat, I)) {
                if (MergingEnabled) {
                    PROF_WARN(
                        "%%m specifier can only be specified once at the end of %s.\n",
                        FilenamePat);
                    return -1;
                }
                MergingEnabled = 1;
                if (FilenamePat[I] == 'm')
                    lprofCurFilename.MergePoolSize = 1;
                else {
                    lprofCurFilename.MergePoolSize = FilenamePat[I] - '0';
                    I++; /* advance to 'm' */
                }
            }
        }

    lprofCurFilename.NumPids = NumPids;
    lprofCurFilename.NumHosts = NumHosts;
    return 0;
}
/* Read profile data in \c ProfileFile and merge with in-memory
   profile counters. Returns -1 if there is fatal error, otheriwse
   0 is returned.
*/
static int doProfileMerging(FILE *ProfileFile) {
    uint64_t ProfileFileSize;
    char *ProfileBuffer;

    if (fseek(ProfileFile, 0L, SEEK_END) == -1) {
        PROF_ERR("Unable to merge profile data, unable to get size: %s\n",
                 strerror(errno));
        return -1;
    }
    ProfileFileSize = ftell(ProfileFile);

    /* Restore file offset.  */
    if (fseek(ProfileFile, 0L, SEEK_SET) == -1) {
        PROF_ERR("Unable to merge profile data, unable to rewind: %s\n",
                 strerror(errno));
        return -1;
    }

    /* Nothing to merge.  */
    if (ProfileFileSize < sizeof(__llvm_profile_header)) {
        if (ProfileFileSize)
            PROF_WARN("Unable to merge profile data: %s\n",
                      "source profile file is too small.");
        return 0;
    }

    ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE,
                         fileno(ProfileFile), 0);
    if (ProfileBuffer == MAP_FAILED) {
        PROF_ERR("Unable to merge profile data, mmap failed: %s\n",
                 strerror(errno));
        return -1;
    }

    if (__llvm_profile_check_compatibility(ProfileBuffer, ProfileFileSize)) {
        (void)munmap(ProfileBuffer, ProfileFileSize);
        PROF_WARN("Unable to merge profile data: %s\n",
                  "source profile file is not compatible.");
        return 0;
    }

    /* Now start merging */
    __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize);
    (void)munmap(ProfileBuffer, ProfileFileSize);

    return 0;
}
COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) {
  FILE *f;
  int fd;
#ifdef COMPILER_RT_HAS_FCNTL_LCK
  fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
  if (fd < 0)
    return NULL;

  if (lprofLockFd(fd) != 0)
    PROF_WARN("Data may be corrupted during profile merging : %s\n",
              "Fail to obtain file lock due to system limit.");

  f = fdopen(fd, "r+b");
#elif defined(_WIN32)
  // FIXME: Use the wide variants to handle Unicode filenames.
  HANDLE h = CreateFileA(ProfileName, GENERIC_READ | GENERIC_WRITE, 0, 0,
                         OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  if (h == INVALID_HANDLE_VALUE)
    return NULL;

  fd = _open_osfhandle((intptr_t)h, 0);
  if (fd == -1) {
    CloseHandle(h);
    return NULL;
  }

  f = _fdopen(fd, "r+b");
  if (f == 0) {
    CloseHandle(h);
    return NULL;
  }
#else
  /* Worst case no locking applied.  */
  PROF_WARN("Concurrent file access is not supported : %s\n",
            "lack file locking");
  fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
  if (fd < 0)
    return NULL;
  f = fdopen(fd, "r+b");
#endif

  return f;
}