<commit_before>#include <atomic>
#include "percpu.hh"

class filetable {
private:
  static const int cpushift = 16;
  static const int fdmask = (1 << cpushift) - 1;

public:
  static filetable* alloc() {
    return new filetable();
  }

  filetable* copy() {
    filetable* t = new filetable(false);

    for(int cpu = 0; cpu < NCPU; cpu++) {
      for(int fd = 0; fd < NOFILE; fd++) {
        sref<file> f;
        if (getfile((cpu << cpushift) | fd, &f)) {
          f->inc();
          t->ofile_[cpu][fd].store(f.get(), std::memory_order_relaxed);
        } else {
          t->ofile_[cpu][fd].store(nullptr, std::memory_order_relaxed);
        }
      }
    }
    std::atomic_thread_fence(std::memory_order_release);
    return t;
  }
  
  bool getfile(int fd, sref<file> *sf) {
    int cpu = fd >> cpushift;
    fd = fd & fdmask;

    if (cpu < 0 || cpu >= NCPU)
      return false;

    if (fd < 0 || fd >= NOFILE)
      return false;

    scoped_gc_epoch gc;
    file* f = ofile_[cpu][fd];
    if (!f || !sf->init_nonzero(f))
      return false;
    return true;
  }

  int allocfd(struct file *f, bool percpu = false) {
    int cpu = percpu ? myid() : 0;
    for (int fd = 0; fd < NOFILE; fd++)
      if (ofile_[cpu][fd] == nullptr && cmpxch(&ofile_[cpu][fd], (file*)nullptr, f))
        return (cpu << cpushift) | fd;
    cprintf("filetable::allocfd: failed\n");
    return -1;
  }

  void close(int fd) {
    // XXX(sbw) if f->ref_ > 1 the kernel will not actually close 
    // the file when this function returns (i.e. sys_close can return 
    // while the file/pipe/socket is still open).
    int cpu = fd >> cpushift;
    fd = fd & fdmask;

    if (cpu < 0 || cpu >= NCPU) {
      cprintf("filetable::close: bad fd cpu %u\n", cpu);
      return;
    }

    if (fd < 0 || fd >= NOFILE) {
      cprintf("filetable::close: bad fd %u\n", fd);
      return;
    }

    file* f = ofile_[cpu][fd].exchange(nullptr);
    if (f != nullptr)
      f->dec();
    else
      cprintf("filetable::close: bad fd %u\n", fd);
  }

  void decref() {
    if (--ref_ == 0)
      delete this;
  }

  void incref() {
    ref_++;
  }

private:
  filetable(bool clear = true) : ref_(1) {
    if (!clear)
      return;
    for(int cpu = 0; cpu < NCPU; cpu++)
      for(int fd = 0; fd < NOFILE; fd++)
        ofile_[cpu][fd].store(nullptr, std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_release);
  }

  ~filetable() {
    for(int cpu = 0; cpu < NCPU; cpu++){
      for(int fd = 0; fd < NOFILE; fd++){
        if (ofile_[cpu][fd].load() != nullptr) {
          ofile_[cpu][fd].load()->dec();
          ofile_[cpu][fd] = nullptr;
        }
      }
    }
  }

  filetable& operator=(const filetable&);
  filetable(const filetable& x);
  NEW_DELETE_OPS(filetable);  

  percpu<std::atomic<file*>[NOFILE]> ofile_;
  std::atomic<u64> ref_;
};
<commit_msg>filetable: Don't use getfile in filetable::copy<commit_after>#include <atomic>
#include "percpu.hh"

class filetable {
private:
  static const int cpushift = 16;
  static const int fdmask = (1 << cpushift) - 1;

public:
  static filetable* alloc() {
    return new filetable();
  }

  filetable* copy() {
    filetable* t = new filetable(false);

    scoped_gc_epoch gc;
    for(int cpu = 0; cpu < NCPU; cpu++) {
      for(int fd = 0; fd < NOFILE; fd++) {
        file *f = ofile_[cpu][fd];
        if (f) {
          f->inc();
          t->ofile_[cpu][fd].store(f, std::memory_order_relaxed);
        } else {
          t->ofile_[cpu][fd].store(nullptr, std::memory_order_relaxed);
        }
      }
    }
    std::atomic_thread_fence(std::memory_order_release);
    return t;
  }
  
  bool getfile(int fd, sref<file> *sf) {
    int cpu = fd >> cpushift;
    fd = fd & fdmask;

    if (cpu < 0 || cpu >= NCPU)
      return false;

    if (fd < 0 || fd >= NOFILE)
      return false;

    scoped_gc_epoch gc;
    file* f = ofile_[cpu][fd];
    if (!f || !sf->init_nonzero(f))
      return false;
    return true;
  }

  int allocfd(struct file *f, bool percpu = false) {
    int cpu = percpu ? myid() : 0;
    for (int fd = 0; fd < NOFILE; fd++)
      if (ofile_[cpu][fd] == nullptr && cmpxch(&ofile_[cpu][fd], (file*)nullptr, f))
        return (cpu << cpushift) | fd;
    cprintf("filetable::allocfd: failed\n");
    return -1;
  }

  void close(int fd) {
    // XXX(sbw) if f->ref_ > 1 the kernel will not actually close 
    // the file when this function returns (i.e. sys_close can return 
    // while the file/pipe/socket is still open).
    int cpu = fd >> cpushift;
    fd = fd & fdmask;

    if (cpu < 0 || cpu >= NCPU) {
      cprintf("filetable::close: bad fd cpu %u\n", cpu);
      return;
    }

    if (fd < 0 || fd >= NOFILE) {
      cprintf("filetable::close: bad fd %u\n", fd);
      return;
    }

    file* f = ofile_[cpu][fd].exchange(nullptr);
    if (f != nullptr)
      f->dec();
    else
      cprintf("filetable::close: bad fd %u\n", fd);
  }

  void decref() {
    if (--ref_ == 0)
      delete this;
  }

  void incref() {
    ref_++;
  }

private:
  filetable(bool clear = true) : ref_(1) {
    if (!clear)
      return;
    for(int cpu = 0; cpu < NCPU; cpu++)
      for(int fd = 0; fd < NOFILE; fd++)
        ofile_[cpu][fd].store(nullptr, std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_release);
  }

  ~filetable() {
    for(int cpu = 0; cpu < NCPU; cpu++){
      for(int fd = 0; fd < NOFILE; fd++){
        if (ofile_[cpu][fd].load() != nullptr) {
          ofile_[cpu][fd].load()->dec();
          ofile_[cpu][fd] = nullptr;
        }
      }
    }
  }

  filetable& operator=(const filetable&);
  filetable(const filetable& x);
  NEW_DELETE_OPS(filetable);  

  percpu<std::atomic<file*>[NOFILE]> ofile_;
  std::atomic<u64> ref_;
};

{'fraction_non_alphanumeric': 0.16710046850598648, 'fraction_numerical': 0.007634912372028457, 'mean_word_length': 2.426872770511296, 'pattern_counts': {'":': 0, '<': 46, '<?xml version=': 0, '>': 46, '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': '5354776', 'n_tokens_mistral': 2170, 'n_tokens_neox': 2097, 'n_words': 537}