<commit_before>#include "iodine.h"

#include <ruby/thread.h>

#include <stdint.h>
// clang-format on

#include "facil.h"
#include <spnlock.inc>

#include <pthread.h>

/* *****************************************************************************
IO flushing dedicated thread for protection against blocking code
***************************************************************************** */

static volatile int sock_io_thread = 0;
static pthread_t sock_io_pthread;
typedef struct {
  size_t threads;
  size_t processes;
} iodine_start_settings_s;

static void *iodine_io_thread(void *arg) {
  (void)arg;
  struct timespec tm;
  while (sock_io_thread) {
    sock_flush_all();
    tm = (struct timespec){.tv_nsec = 0, .tv_sec = 1};
    nanosleep(&tm, NULL);
  }
  return NULL;
}
static void iodine_start_io_thread(void) {
  sock_io_thread = 1;
  pthread_create(&sock_io_pthread, NULL, iodine_io_thread, NULL);
}
static void iodine_join_io_thread(void) {
  sock_io_thread = 0;
  if (sock_io_pthread) {
    pthread_join(sock_io_pthread, NULL);
  }
  sock_io_pthread = NULL;
}

/* *****************************************************************************
The Defer library overriding functions
***************************************************************************** */

/* used to create Ruby threads and pass them the information they need */
struct CreateThreadArgs {
  void *(*thread_func)(void *);
  void *arg;
  spn_lock_i lock;
};

/* used for GVL signalling */
void call_async_signal(void *pool) { defer_pool_stop((pool_pt)pool); }

static void *defer_thread_start(void *args_) {
  struct CreateThreadArgs *args = args_;
  IodineCaller.set_GVL(0);
  args->thread_func(args->arg);
  return NULL;
}

/* the thread's GVL release */
static VALUE defer_thread_inGVL(void *args_) {
  struct CreateThreadArgs *old_args = args_;
  struct CreateThreadArgs args = *old_args;
  IodineCaller.set_GVL(1);
  spn_unlock(&old_args->lock);
  rb_thread_call_without_gvl(defer_thread_start, args_,
                             (void (*)(void *))call_async_signal, args.arg);
  return Qnil;
}

/* Within the GVL, creates a Ruby thread using an API call */
static void *create_ruby_thread_gvl(void *args) {
  return (void *)IodineStore.add(rb_thread_create(defer_thread_inGVL, args));
}

/* Runs the before / after fork callbacks (if `before` is true, before runs) */
static void iodine_perform_fork_callbacks(uint8_t before);

static void *fork_using_ruby(void *ignr) {
  // stop IO thread and call before_fork callbacks
  if (sock_io_pthread) {
    iodine_join_io_thread();
  }
  iodine_perform_fork_callbacks(1);
  // fork
  const VALUE ProcessClass = rb_const_get(rb_cObject, rb_intern2("Process", 7));
  const VALUE rb_pid = IodineCaller.call(ProcessClass, rb_intern2("fork", 4));
  intptr_t pid = 0;<commit_msg>oops, don't use obsolete stack memory<commit_after>#include "iodine.h"

#include <ruby/thread.h>

#include <stdint.h>
// clang-format on

#include "facil.h"
#include <spnlock.inc>

#include <pthread.h>

/* *****************************************************************************
IO flushing dedicated thread for protection against blocking code
***************************************************************************** */

static volatile int sock_io_thread = 0;
static pthread_t sock_io_pthread;
typedef struct {
  size_t threads;
  size_t processes;
} iodine_start_settings_s;

static void *iodine_io_thread(void *arg) {
  (void)arg;
  struct timespec tm;
  while (sock_io_thread) {
    sock_flush_all();
    tm = (struct timespec){.tv_nsec = 0, .tv_sec = 1};
    nanosleep(&tm, NULL);
  }
  return NULL;
}
static void iodine_start_io_thread(void) {
  if (!sock_io_thread) {
    sock_io_thread = 1;
    pthread_create(&sock_io_pthread, NULL, iodine_io_thread, NULL);
  }
}
static void iodine_join_io_thread(void) {
  if (sock_io_thread) {
    sock_io_thread = 0;
    pthread_join(sock_io_pthread, NULL);
  }
  sock_io_pthread = NULL;
}

/* *****************************************************************************
The Defer library overriding functions
***************************************************************************** */

/* used to create Ruby threads and pass them the information they need */
struct CreateThreadArgs {
  void *(*thread_func)(void *);
  void *arg;
  spn_lock_i lock;
};

/* used for GVL signalling */
void call_async_signal(void *pool) { defer_pool_stop((pool_pt)pool); }

static void *defer_thread_start(void *args_) {
  struct CreateThreadArgs *args = args_;
  IodineCaller.set_GVL(0);
  args->thread_func(args->arg);
  return NULL;
}

/* the thread's GVL release */
static VALUE defer_thread_inGVL(void *args_) {
  struct CreateThreadArgs *old_args = args_;
  struct CreateThreadArgs args = *old_args;
  IodineCaller.set_GVL(1);
  spn_unlock(&old_args->lock);
  rb_thread_call_without_gvl(defer_thread_start, &args,
                             (void (*)(void *))call_async_signal, args.arg);
  return Qnil;
}

/* Within the GVL, creates a Ruby thread using an API call */
static void *create_ruby_thread_gvl(void *args) {
  return (void *)IodineStore.add(rb_thread_create(defer_thread_inGVL, args));
}

/* Runs the before / after fork callbacks (if `before` is true, before runs) */
static void iodine_perform_fork_callbacks(uint8_t before);

static void *fork_using_ruby(void *ignr) {
  // stop IO thread and call before_fork callbacks
  if (sock_io_pthread) {
    iodine_join_io_thread();
  }
  iodine_perform_fork_callbacks(1);
  // fork
  const VALUE ProcessClass = rb_const_get(rb_cObject, rb_intern2("Process", 7));
  const VALUE rb_pid = IodineCaller.call(ProcessClass, rb_intern2("fork", 4));
  intptr_t pid = 0;
{'fraction_non_alphanumeric': 0.20865587614356088, 'fraction_numerical': 0.0049261083743842365, 'mean_word_length': 5.19281045751634, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2195158', 'n_tokens_mistral': 1939, 'n_tokens_neox': 1831, 'n_words': 438}