/*
  This file is part of CDO. CDO is a collection of Operators to
  manipulate and analyse Climate model Data.

  Copyright (C) 2003-2020 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
  See COPYING file for copying and redistribution conditions.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; version 2 of the License.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef HAVE_GETRLIMIT
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/time.h>     // getrlimit
#include <sys/resource.h> // getrlimit
#endif
#endif

#include <cstdio>
#include <algorithm>

#include "cdo_rlimit.h"
#include "cdo_options.h"
#include "mpmo.h"


#ifdef SX
#define RLIM_T long long
#else
#define RLIM_T rlim_t
#endif


#define PRINT_RLIMIT(resource)                                          \
  {                                                                                      \
    struct rlimit rlim;                                                                  \
    const auto status = getrlimit(resource, &rlim);                                      \
    if (status == 0)                                                                     \
      {                                                                                  \
        if (sizeof(RLIM_T) > sizeof(long))                                               \
          {                                                                              \
            fprintf(stderr, "CUR %-15s = %llu\n", #resource, (long long) rlim.rlim_cur); \
            fprintf(stderr, "MAX %-15s = %llu\n", #resource, (long long) rlim.rlim_max); \
          }                                                                              \
        else                                                                             \
          {                                                                              \
            fprintf(stderr, "CUR %-15s = %lu\n", #resource, (long) rlim.rlim_cur);       \
            fprintf(stderr, "MAX %-15s = %lu\n", #resource, (long) rlim.rlim_max);       \
          }                                                                              \
      }                                                                                  \
  }

namespace cdo
{

void
print_rlimits(void)
{
#ifdef HAVE_GETRLIMIT
#ifdef RLIMIT_FSIZE
  PRINT_RLIMIT(RLIMIT_FSIZE);
#endif
#ifdef RLIMIT_NOFILE
  PRINT_RLIMIT(RLIMIT_NOFILE);
#endif
#ifdef RLIMIT_STACK
  PRINT_RLIMIT(RLIMIT_STACK);
#endif
#ifdef RLIMIT_RSS
  PRINT_RLIMIT(RLIMIT_RSS);
#endif
#endif
}

void
set_numfiles(long numfiles)
{
#ifdef HAVE_GETRLIMIT
#ifdef RLIMIT_NOFILE
  const int resource = RLIMIT_NOFILE;
  struct rlimit lim;
  auto stat = getrlimit(resource, &lim);
  if (stat == 0)
    {
      RLIM_T min_size = numfiles;
      min_size = std::min(min_size, lim.rlim_max);
      if (lim.rlim_cur < min_size)
        {
          lim.rlim_cur = min_size;

          stat = setrlimit(resource, &lim);
          if (MpMO::DebugLevel > 0)
            {
              if (stat == 0)
                {
                  fprintf(stderr, "Set numfiles to %ld\n", (long) min_size);
                  PRINT_RLIMIT(RLIMIT_NOFILE);
                }
              else
                fprintf(stderr, "Set numfiles to %ld failed!\n", (long) min_size);
              fprintf(stderr, "\n");
            }
        }
    }
#endif
#endif
}

void
set_stacksize(long stacksize)
{
#ifdef HAVE_GETRLIMIT
#ifdef RLIMIT_STACK
  const int resource = RLIMIT_STACK;
  struct rlimit lim;
  auto stat = getrlimit(resource, &lim);
  if (stat == 0)
    {
      RLIM_T min_size = stacksize;
      min_size = std::min(min_size, lim.rlim_max);
      if (lim.rlim_cur < min_size)
        {
          lim.rlim_cur = min_size;

          stat = setrlimit(resource, &lim);
          if (MpMO::DebugLevel > 0)
            {
              if (stat == 0)
                {
                  fprintf(stderr, "Set stacksize to %ld\n", (long) min_size);
                  PRINT_RLIMIT(RLIMIT_STACK);
                }
              else
                fprintf(stderr, "Set stacksize to %ld failed!\n", (long) min_size);
              fprintf(stderr, "\n");
            }
        }
    }
#endif
#endif
}

} // namespace cdo
