<commit_before>/*
 * Shared memory for sharing data between worker processes.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "shm.hxx"
#include "system/Error.hxx"
#include "util/RefCount.hxx"

#include <inline/poison.h>
#include <daemon/log.h>

#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/intrusive/set.hpp>

#include <assert.h>
#include <stdint.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>

struct shm {
    RefCount ref;

    const size_t page_size;
    const unsigned num_pages;

    /** this lock protects the linked list */
    boost::interprocess::interprocess_mutex mutex;

    struct Page
        : boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {
        unsigned num_pages;
        uint8_t *data;

        bool operator<(const Page &other) const {
            return this < &other;
        }
    };

    typedef boost::intrusive::set<Page,
                                  boost::intrusive::constant_time_size<false>> PageList;

    PageList available;
    Page pages[1];

    shm(size_t _page_size, unsigned _num_pages)
        :page_size(_page_size), num_pages(_num_pages) {
        ref.Init();

        pages[0].num_pages = num_pages;
        pages[0].data = GetData();
        available.push_front(pages[0]);
    }

    static unsigned CalcHeaderPages(size_t page_size, unsigned num_pages) {
        size_t header_size = sizeof(struct shm) +
            (num_pages - 1) * sizeof(Page);
        return (header_size + page_size - 1) / page_size;
    }

    unsigned CalcHeaderPages() const {
        return CalcHeaderPages(page_size, num_pages);
    }

    uint8_t *At(size_t offset) {
        return (uint8_t *)this + offset;
    }

    const uint8_t *At(size_t offset) const {
        return (const uint8_t *)this + offset;
    }

    uint8_t *GetData() {
        return At(page_size * CalcHeaderPages());
    }

    const uint8_t *GetData() const {
        return At(page_size * CalcHeaderPages());
    }

    unsigned PageNumber(const Page &page) const {
        return &page - &pages[0];
    }

    unsigned PageNumber(const void *p) const {
        ptrdiff_t difference = (const uint8_t *)p - GetData();
        unsigned page_number = difference / page_size;
        assert(difference % page_size == 0);

        assert(page_number < num_pages);

        return page_number;
    }

    Page *FindAvailable(unsigned want_pages);
    Page *SplitPage(Page *page, unsigned want_pages);

    /**
     * Merge this page with its adjacent pages if possible, to create
     * bigger "available" areas.
     */
    void Merge(Page *page);

    void *Allocate(unsigned want_pages);
    void Free(const void *p);
};

struct shm *
shm_new(size_t page_size, unsigned num_pages)
{
    assert(page_size >= sizeof(size_t));
    assert(num_pages > 0);

    const unsigned header_pages = shm::CalcHeaderPages(page_size, num_pages);
    void *p = mmap(nullptr, page_size * (header_pages + num_pages),
                   PROT_READ|PROT_WRITE,
                   MAP_ANONYMOUS|MAP_SHARED,
                   -1, 0);
    if (p == (void *)-1)
        throw MakeErrno("mmap() failed");

    return ::new(p) struct shm(page_size, num_pages);
}

void
shm_ref(struct shm *shm)
{
    assert(shm != nullptr);

    shm->ref.Get();
}

void
shm_close(struct shm *shm)
{
    unsigned header_pages;
    int ret;

    assert(shm != nullptr);

    if (shm->ref.Put())
        shm->~shm();

    header_pages = shm->CalcHeaderPages();
    ret = munmap(shm, shm->page_size * (header_pages + shm->num_pages));
    if (ret < 0)
        daemon_log(1, "munmap() failed: %s\n", strerror(errno));
}

size_t
shm_page_size(const struct shm *shm)
{
    return shm->page_size;
}

shm::Page *
shm::FindAvailable(unsigned want_pages)
{
    for (auto &page : available)
        if (page.num_pages >= want_pages)
            return &page;

    return nullptr;
}

shm::Page *
shm::SplitPage(Page *page, unsigned want_pages)
{
    assert(page->num_pages > want_pages);

    page->num_pages -= want_pages;

    page[page->num_pages].data = page->data + page_size * page->num_pages;
    page += page->num_pages;
    page->num_pages = want_pages;

    return page;
}

void *
shm::Allocate(unsigned want_pages)
{
    assert(want_pages > 0);

    boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> lock(mutex);

    Page *page = FindAvailable(want_pages);
    if (page == nullptr)
        return nullptr;

    assert(available.iterator_to(*page) == available.begin() ||
           &*std::prev(available.iterator_to(*page)) < page);
    assert(std::next(available.iterator_to(*page)) == available.end() ||
           &*std::next(available.iterator_to(*page)) > page);

    assert(page->num_pages >= want_pages);

    if (page->num_pages == want_pages) {
        available.erase(available.iterator_to(*page));

        lock.unlock();

        poison_undefined(page->data, page_size * want_pages);
        return page->data;
    } else {
        page = SplitPage(page, want_pages);

        lock.unlock();

        poison_undefined(page->data, page_size * want_pages);
        return page->data;
    }
}

void *
shm_alloc(struct shm *shm, unsigned want_pages)
{
    return shm->Allocate(want_pages);
}

/** merge this page with its adjacent pages if possible, to create
    bigger "available" areas */
void
shm::Merge(Page *page)
{
    unsigned page_number = PageNumber(*page);

    /* merge with previous page? */

    assert(available.iterator_to(*page) == available.begin() ||
           &*std::prev(available.iterator_to(*page)) < page);

    auto i = available.iterator_to(*page);

    if (i != available.begin()) {
        Page &previous = *std::prev(i);
        if (PageNumber(previous) + previous.num_pages == page_number) {
            previous.num_pages += page->num_pages;
            available.erase(i);

            page = &previous;
            page_number = PageNumber(*page);
            i = available.iterator_to(*page);
        }
    }

    /* merge with next page? */

    assert(std::next(available.iterator_to(*page)) == available.end() ||
           &*std::next(available.iterator_to(*page)) > page);

    if (i != std::prev(available.end())) {
        Page &next = *std::next(i);

        if (page_number + page->num_pages == PageNumber(next)) {
            page->num_pages += next.num_pages;
            available.erase(available.iterator_to(next));
        }
    }
}

void
shm::Free(const void *p)
{
    unsigned page_number = PageNumber(p);
    Page *page = &pages[page_number];

    poison_noaccess(page->data, page_size * page->num_pages);

    boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> lock(mutex);

    available.insert(*page);

    Merge(page);
}

void
shm_free(struct shm *shm, const void *p)
{
    shm->Free(p);
}
<commit_msg>shm/shm: compare Page pointers in Merge(), eliminate page_number<commit_after>/*
 * Shared memory for sharing data between worker processes.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "shm.hxx"
#include "system/Error.hxx"
#include "util/RefCount.hxx"

#include <inline/poison.h>
#include <daemon/log.h>

#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/intrusive/set.hpp>

#include <assert.h>
#include <stdint.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>

struct shm {
    RefCount ref;

    const size_t page_size;
    const unsigned num_pages;

    /** this lock protects the linked list */
    boost::interprocess::interprocess_mutex mutex;

    struct Page
        : boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {
        unsigned num_pages;
        uint8_t *data;

        bool operator<(const Page &other) const {
            return this < &other;
        }
    };

    typedef boost::intrusive::set<Page,
                                  boost::intrusive::constant_time_size<false>> PageList;

    PageList available;
    Page pages[1];

    shm(size_t _page_size, unsigned _num_pages)
        :page_size(_page_size), num_pages(_num_pages) {
        ref.Init();

        pages[0].num_pages = num_pages;
        pages[0].data = GetData();
        available.push_front(pages[0]);
    }

    static unsigned CalcHeaderPages(size_t page_size, unsigned num_pages) {
        size_t header_size = sizeof(struct shm) +
            (num_pages - 1) * sizeof(Page);
        return (header_size + page_size - 1) / page_size;
    }

    unsigned CalcHeaderPages() const {
        return CalcHeaderPages(page_size, num_pages);
    }

    uint8_t *At(size_t offset) {
        return (uint8_t *)this + offset;
    }

    const uint8_t *At(size_t offset) const {
        return (const uint8_t *)this + offset;
    }

    uint8_t *GetData() {
        return At(page_size * CalcHeaderPages());
    }

    const uint8_t *GetData() const {
        return At(page_size * CalcHeaderPages());
    }

    unsigned PageNumber(const Page &page) const {
        return &page - &pages[0];
    }

    unsigned PageNumber(const void *p) const {
        ptrdiff_t difference = (const uint8_t *)p - GetData();
        unsigned page_number = difference / page_size;
        assert(difference % page_size == 0);

        assert(page_number < num_pages);

        return page_number;
    }

    Page *FindAvailable(unsigned want_pages);
    Page *SplitPage(Page *page, unsigned want_pages);

    /**
     * Merge this page with its adjacent pages if possible, to create
     * bigger "available" areas.
     */
    void Merge(Page *page);

    void *Allocate(unsigned want_pages);
    void Free(const void *p);
};

struct shm *
shm_new(size_t page_size, unsigned num_pages)
{
    assert(page_size >= sizeof(size_t));
    assert(num_pages > 0);

    const unsigned header_pages = shm::CalcHeaderPages(page_size, num_pages);
    void *p = mmap(nullptr, page_size * (header_pages + num_pages),
                   PROT_READ|PROT_WRITE,
                   MAP_ANONYMOUS|MAP_SHARED,
                   -1, 0);
    if (p == (void *)-1)
        throw MakeErrno("mmap() failed");

    return ::new(p) struct shm(page_size, num_pages);
}

void
shm_ref(struct shm *shm)
{
    assert(shm != nullptr);

    shm->ref.Get();
}

void
shm_close(struct shm *shm)
{
    unsigned header_pages;
    int ret;

    assert(shm != nullptr);

    if (shm->ref.Put())
        shm->~shm();

    header_pages = shm->CalcHeaderPages();
    ret = munmap(shm, shm->page_size * (header_pages + shm->num_pages));
    if (ret < 0)
        daemon_log(1, "munmap() failed: %s\n", strerror(errno));
}

size_t
shm_page_size(const struct shm *shm)
{
    return shm->page_size;
}

shm::Page *
shm::FindAvailable(unsigned want_pages)
{
    for (auto &page : available)
        if (page.num_pages >= want_pages)
            return &page;

    return nullptr;
}

shm::Page *
shm::SplitPage(Page *page, unsigned want_pages)
{
    assert(page->num_pages > want_pages);

    page->num_pages -= want_pages;

    page[page->num_pages].data = page->data + page_size * page->num_pages;
    page += page->num_pages;
    page->num_pages = want_pages;

    return page;
}

void *
shm::Allocate(unsigned want_pages)
{
    assert(want_pages > 0);

    boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> lock(mutex);

    Page *page = FindAvailable(want_pages);
    if (page == nullptr)
        return nullptr;

    assert(available.iterator_to(*page) == available.begin() ||
           &*std::prev(available.iterator_to(*page)) < page);
    assert(std::next(available.iterator_to(*page)) == available.end() ||
           &*std::next(available.iterator_to(*page)) > page);

    assert(page->num_pages >= want_pages);

    if (page->num_pages == want_pages) {
        available.erase(available.iterator_to(*page));

        lock.unlock();

        poison_undefined(page->data, page_size * want_pages);
        return page->data;
    } else {
        page = SplitPage(page, want_pages);

        lock.unlock();

        poison_undefined(page->data, page_size * want_pages);
        return page->data;
    }
}

void *
shm_alloc(struct shm *shm, unsigned want_pages)
{
    return shm->Allocate(want_pages);
}

/** merge this page with its adjacent pages if possible, to create
    bigger "available" areas */
void
shm::Merge(Page *page)
{
    /* merge with previous page? */

    assert(available.iterator_to(*page) == available.begin() ||
           &*std::prev(available.iterator_to(*page)) < page);

    auto i = available.iterator_to(*page);

    if (i != available.begin()) {
        Page &previous = *std::prev(i);
        if (&previous + previous.num_pages == page) {
            previous.num_pages += page->num_pages;
            available.erase(i);

            page = &previous;
            i = available.iterator_to(*page);
        }
    }

    /* merge with next page? */

    assert(std::next(available.iterator_to(*page)) == available.end() ||
           &*std::next(available.iterator_to(*page)) > page);

    if (i != std::prev(available.end())) {
        Page &next = *std::next(i);

        if (page + page->num_pages == &next) {
            page->num_pages += next.num_pages;
            available.erase(available.iterator_to(next));
        }
    }
}

void
shm::Free(const void *p)
{
    unsigned page_number = PageNumber(p);
    Page *page = &pages[page_number];

    poison_noaccess(page->data, page_size * page->num_pages);

    boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> lock(mutex);

    available.insert(*page);

    Merge(page);
}

void
shm_free(struct shm *shm, const void *p)
{
    shm->Free(p);
}
<|endoftext|>


<commit_before>#include <pthread.h>
#include <string.h>
#include <string>
#include <stdint.h>
#include <unistd.h>
#include <re.h>
#include <vector>

#include "sipua.hpp"
#include "stack.hpp"

struct tmr base_timer;

static int count = 0;
static uint64_t start_time = 0;
static uint64_t tick = 0;
static std::vector<SIPUE*> ues;

static void cleanup()
{

    for (SIPUE* a : ues)
    {
        delete a;
    }

    close_sip_stacks(false);
}

static void timer_fn(void* arg)
{
//    printf("Called on timer!\n");
    uint64_t next_tick = start_time + (10*tick);
    int diff = next_tick - tmr_jiffies();
    if (diff > 0)
    {
        tmr_start(&base_timer, diff, timer_fn, NULL);
        return;
    }

    count++;
    if (count < 10000)
    {
        tick++;
        int ms_to_sleep = diff + 10;
        if (ms_to_sleep > 0)
            ms_to_sleep = 0;
        tmr_start(&base_timer, ms_to_sleep, timer_fn, NULL);
        SIPUE* a = new SIPUE("sip:127.0.0.1",
                             "sip:1234@127.0.0.1",
                             "1234@127.0.0.1",
                             "secret");
        a->register_ue();
        ues.push_back(a);
    }
    else
    {
        cleanup();
    }
}

int main(int argc, char *argv[])
{
    int err; /* errno return values */

    /* initialize libre state */
    err = libre_init();
    fd_setsize(50000);
    if (err) {
        re_fprintf(stderr, "re init failed: %s\n", strerror(err));
    }

    re_init_timer_heap();

    tmr_init(&base_timer);
    tmr_start(&base_timer, 0, timer_fn, NULL);

    create_sip_stacks(20);
    start_time = tmr_jiffies();
    re_main(NULL);
    printf("End of loop\n");

    free_sip_stacks();
    libre_close();

    /* check for memory leaks */
    //tmr_debug();
    mem_debug();

    return 0;
}
<commit_msg>Refactor timer function<commit_after>#include <pthread.h>
#include <string.h>
#include <string>
#include <stdint.h>
#include <unistd.h>
#include <re.h>
#include <vector>

#include "sipua.hpp"
#include "stack.hpp"

static uint64_t max_ues = 10000;
static std::vector<SIPUE*> ues;

class RepeatingTimer
{
public:
    RepeatingTimer(unsigned int ms_per_tick) :
        _ms_per_tick(ms_per_tick),
        _tick(0)
    {};
    virtual ~RepeatingTimer() = default;

    void start();
    static void static_timer_fn(void* arg);
    void timer_fn();

    uint64_t ms_since_start();

    virtual bool act() = 0;

protected:
    unsigned int _ms_per_tick;
    struct tmr _timer;
    uint64_t _start_time;
    uint64_t _tick;
};

class InitialRegistrar : public RepeatingTimer
{
public:
    InitialRegistrar() : RepeatingTimer(10) {};

    bool act();
    bool everything_registered() { return _actual_ues_registered == max_ues; }
private:
    uint64_t _actual_ues_registered = 0;
    double _registers_per_ms = 0.7;
};

class CallScheduler : public RepeatingTimer
{
public:
    CallScheduler(InitialRegistrar* registrar) : RepeatingTimer(1000), _registrar(registrar) {};

    bool act();
private:
    InitialRegistrar* _registrar;
};

static void cleanup()
{
    for (SIPUE* a : ues)
    {
        delete a;
    }

    close_sip_stacks(false);
}

void RepeatingTimer::static_timer_fn(void* arg)
{
    RepeatingTimer* t = static_cast<RepeatingTimer*>(arg);

    t->timer_fn();
}

void RepeatingTimer::start()
{
    _start_time = tmr_jiffies();
    tmr_init(&_timer);
    tmr_start(&_timer, 0, static_timer_fn, this);
}

uint64_t RepeatingTimer::ms_since_start()
{
    return tmr_jiffies() - _start_time;
}

void RepeatingTimer::timer_fn()
{
    uint64_t next_tick = _start_time + (_ms_per_tick * _tick);
    int diff = next_tick - tmr_jiffies();
    if (diff > 0)
    {
        //printf("A: Rescheduling %p for %d ms\n", this, diff);
        tmr_start(&_timer, diff, static_timer_fn, this);
        return;
    }

    _tick++;
    bool reschedule_timer = act();

    if (reschedule_timer)
    {
        int ms_to_sleep = diff + _ms_per_tick;
        if (ms_to_sleep < 0)
            ms_to_sleep = 0;
        //printf("B: Rescheduling %p for %d ms\n", this, ms_to_sleep);
        tmr_start(&_timer, ms_to_sleep, static_timer_fn, this);
    }
}

bool InitialRegistrar::act()
{
    if (_actual_ues_registered == max_ues)
    {
 //       cleanup();
        return false;
    }

    uint64_t expected_ues_registered = ms_since_start() * _registers_per_ms;
    expected_ues_registered = std::min(expected_ues_registered, max_ues);
    int ues_to_register = expected_ues_registered - _actual_ues_registered;
    //printf("%d UEs to register\n", ues_to_register);
    for (int ii = 0; ii < ues_to_register; ii++)
    {
       SIPUE* a = new SIPUE("sip:127.0.0.1",
                             "sip:1234@127.0.0.1",
                             "1234@127.0.0.1",
                             "secret");
        a->register_ue();
        ues.push_back(a);
        _actual_ues_registered++;
    }

    return true;
}

bool CallScheduler::act()
{
    if (_registrar->everything_registered())
        printf("A calls B\n");
    else
        printf("Still waiting...\n");

    return true;

}
int main(int argc, char *argv[])
{
    int err; /* errno return values */

    /* initialize libre state */
    err = libre_init();
    fd_setsize(50000);
    if (err) {
        re_fprintf(stderr, "re init failed: %s\n", strerror(err));
    }

    re_init_timer_heap();

    InitialRegistrar registering_timer;
    CallScheduler call_scheduler(&registering_timer);

    call_scheduler.start();
    registering_timer.start();

    create_sip_stacks(20);
    re_main(NULL);
    printf("End of loop\n");

    free_sip_stacks();
    libre_close();

    /* check for memory leaks */
    //tmr_debug();
    mem_debug();

    return 0;
}
<|endoftext|>


<commit_before>#include "clause.hpp"
#include "internal.hpp"
#include "macros.hpp"
#include "message.hpp"
#include "proof.hpp"
#include "macros.hpp"

#include <algorithm>

namespace CaDiCaL {

/*------------------------------------------------------------------------*/

// For certain instances it happens quite frequently that learned clauses
// backward subsume some of the recently learned clauses.  Thus whenever we
// learn a clause, we can eagerly check whether one of the last
// 'opts.sublast' learned clauses is subsumed by the new learned clause.
//
// This observation and the idea for this code is due to Donald Knuth (even
// though he originally only tried to subsume the very last clause).  Note
// that 'backward' means the learned clause from which we start the
// subsumption check is checked for subsuming earlier (larger) clauses.

// Check whether the marked 'Internal.clause' subsumes the argument.

inline bool Internal::eagerly_subsume_last_learned (Clause * c) {
  const_literal_iterator end = c->end ();
  size_t found = 0, remain = c->size - clause.size ();
  for (const_literal_iterator i = c->begin (); i != end; i++) {
    int tmp = marked (*i);
    if (tmp < 0) break;
    else if (tmp > 0) found++;
    else if (!remain--) break;
  }
  assert (found <= clause.size ());
  if (found < clause.size ()) return false;
  LOG (c, "learned clauses eagerly subsumes");
  assert (c->redundant);
  mark_garbage (c);
  stats.sublast++;
  return true;
}

// Go over the last 'opts.sublast' clauses and check whether they are
// subsumed by the new clause in 'Internal.clause'.

void Internal::eagerly_subsume_last_learned () {
  START (sublast);
  mark_clause ();
  const_clause_iterator i = clauses.end ();
  int subsumed = 0, tried = 0;
  for (int j = 0; j < opts.sublast; j++) {
    if (i == clauses.begin ()) break;
    Clause * c = *--i;
    if (c->garbage) continue;
    if (!c->redundant) continue;
    if ((size_t) c->size <= clause.size ()) continue;
    LOG (c, "trying to eagerly subsume");
    if (eagerly_subsume_last_learned (c)) subsumed++;
    tried++;
  }
  unmark_clause ();
  LOG ("subsumed eagerly %d clauses out of %d tried", subsumed, tried);
  STOP (sublast);
}

/*------------------------------------------------------------------------*/

// The rest of the file implements a global forward subsumption algorithm,
// which is run frequently during search.  It works both on original
// (irredundant) clauses and on 'sticky' learned clauses which are small
// enough or have a small enough glue to be otherwise kept forever (see
// 'opts.keepsize' and 'opts.keeglue', e.g., a redundant clause is not
// extended and thus kept if its size is smaller equal to 'opts.keepsize' or
// its glue is smaller equal than 'opts.keepsize').  Note, that 'forward'
// means that the clause from which the subsumption check is started is
// checked for being subsumed by other (smaller or equal size) clauses.

bool Internal::subsuming () {

  if (!opts.subsume) return false;

  // Only perform global subsumption checking immediately after a clause
  // reduction happened where the overall allocated memory is small and we
  // got a limit on the number of kept clause in terms of size and glue.
  //
  if (opts.reduce &&
      stats.conflicts != lim.conflicts_at_last_reduce) return false;

  return stats.conflicts >= lim.subsume;
}

// This is the actual subsumption and strengthening check.  We assume that
// all the literals of the candidate clause to be subsumed or strengthened
// are marked, so we only have to check that all the literals of the
// argument clause 'subsuming', which is checked for subsuming the candidate
// clause 'subsumed', has all its literals marked (in the correct phase).
// If exactly one is in the opposite phase we can still strengthen the
// candidate clause by this single literal which occurs in opposite phase.
//
// The result is INT_MIN if all literals are marked and thus the candidate
// clause can be subsumed.  It is zero if neither subsumption nor
// strengthening is possible.  Otherwise the candidate clause can be
// strengthened and as a result the negation of the literal which can be
// removed is returned.

inline int Internal::subsume_check (Clause * subsuming,
                                    Clause * subsumed) {

  // Only use 'subsumed' for these following assertion checks.  Otherwise we
  // only require that 'subsumed' has all its literals marked.
  //
  assert (!subsumed->garbage);
  assert (!subsuming->garbage);
  assert (subsuming != subsumed);
  assert (subsuming->size <= subsumed->size);

  stats.subchecks++;
  const const_literal_iterator end = subsuming->end ();
  int flipped = 0;
  for (const_literal_iterator i = subsuming->begin (); i != end; i++) {
    const int lit = *i, tmp = marked (lit);
    if (!tmp) return 0;
    if (tmp > 0) continue;
    if (flipped) return 0;
    flipped = lit;
  }
  if (!flipped) return INT_MIN;                   // subsumed!!
  else if (!opts.strengthen) return 0;
  else return flipped;                            // strengthen!!
}

/*------------------------------------------------------------------------*/

// Candidate clause 'subsumed' is subsumed by 'subsuming'.

inline void
Internal::subsume_clause (Clause * subsuming, Clause * subsumed) {
  stats.subsumed++;
  assert (subsuming->size <= subsumed->size);
  LOG (subsumed, "subsumed");
  if (subsumed->redundant) stats.subred++; else stats.subirr++;
  mark_garbage (subsumed);
  if (subsumed->redundant || !subsuming->redundant) return;
  LOG ("turning redundant subsuming clause into irredundant clause");
  subsuming->redundant = false;
  stats.irredundant++;
  assert (stats.redundant);
  stats.redundant--;
}

// Candidate clause 'c' is strengthened by removing 'remove'.

inline void Internal::strengthen_clause (Clause * c, int remove) {
  if (watches ()) {
    // An alternative is to remove and update watch lists, which is pretty
    // expensive (quadratic in accumulated in the worst case).  Thus we just
    // skip strengthening this clause if the removed literal is watched.
    if (c->literals[0] == remove ||
        c->literals[1] == remove) return;
  }
  stats.strengthened++;
  assert (c->size > 2);
  LOG (c, "removing %d in", remove);
  if (proof) proof->trace_strengthen_clause (c, remove);
  if (!c->redundant) touch_clause (c);
  const const_literal_iterator end = c->end ();
  literal_iterator j = c->begin ();
  for (const_literal_iterator i = j; i != end; i++)
    if ((*j++ = *i) == remove) j--;
  assert (j + 1 == end);
  dec_bytes (sizeof (int));;
  c->size--;
  if (c->pos > c->size) c->pos = 2;
  if (c->redundant && c->glue > c->size) c->glue = c->size;
  if (c->extended) c->analyzed () = ++stats.analyzed;
  LOG (c, "strengthened");
  check_shrunken_clause (c);
}

/*------------------------------------------------------------------------*/

// Find clauses connected in the occurrence lists 'occs' which subsume the
// candidate clause 'c' given as first argument.  If this is the case the
// clause is subsumed and the result is positive.   If the clause was
// strengthened the result is negative.  Otherwise the candidate clause
// can not be subsumed nor strengthened and zero is returned.

inline int Internal::try_to_subsume_clause (Clause * c,
                                            bool irredundant_only,
					    long old_touched) {

  stats.subtried++;
  assert (!level);
  LOG (c, "trying to subsume");

  mark (c);

  Clause * d = 0;
  int flipped = 0;
  const const_literal_iterator ec = c->end ();
  for (const_literal_iterator i = c->begin (); !d && i != ec; i++) {
    int lit = *i;
    if (irredundant_only &&
        touched (lit) <= old_touched &&
        touched (-lit) <= old_touched)
      continue;
    Occs & os = occs (lit);
    const const_clause_iterator eo = os.end ();
    clause_iterator k = os.begin ();
    for (const_clause_iterator j = k; j != eo; j++) {
      Clause * e = *j;
      if (e->garbage) continue;
      *k++ = e;
      if (d) continue;
      flipped = subsume_check (e, c);
      if (flipped) d = e;                 // ... and leave outer loop.
    }
    os.resize (k - os.begin ());
    shrink_vector (os);
  }

  unmark (c);

  if (flipped == INT_MIN) {
    LOG (d, "subsuming");
    subsume_clause (d, c);
    return 1;
  }

  if (flipped) {
    LOG (d, "strengthening");
    strengthen_clause (c, -flipped);
    return -1;
  }

  return 0;
}

/*------------------------------------------------------------------------*/

// Sorting the scheduled clauses is way faster if we compute save the clause
// size in the schedule to avoid pointer access to clauses during sorting.
// This slightly increases the schedule size though.

struct ClauseSize {
  int size;
  size_t cidx;
  ClauseSize (int s, size_t i) : size (s), cidx (i) { }
};

typedef vector<ClauseSize>::const_iterator const_clause_size_iterator;
typedef vector<ClauseSize>::iterator clause_size_iterator;

struct smaller_clause_size {
  bool operator () (const ClauseSize & a, const ClauseSize & b) const {
    if (a.size < b.size) return true;
    if (a.size > b.size) return false;
    return a.cidx < b.cidx;
  }
};

/*------------------------------------------------------------------------*/

// Usually called from 'subsume' below if 'subsuming' triggered it.  Then
// the idea is to subsume both redundant and irredundant clauses. It is also
// called in the elimination loop in 'elim' in which case we focus on
// irredundant clauses only to help bounded variable elimination.

bool Internal::subsume_round (bool irredundant_only) {

  if (!opts.subsume) return false;

  SWITCH_AND_START (search, simplify, subsume);
  stats.subsumptions++;

  long old_touched = lim.touched_at_last_subsume;
  lim.touched_at_last_subsume = stats.touched;

  assert (!level);

  // Allocate schedule and occurrence lists.
  //
  vector<ClauseSize> schedule;
  init_occs ();

  // Determine candidate clauses and sort them by size.
  //
  const size_t size = clauses.size ();
  for (size_t i = 0; i != size; i++) {
    Clause * c = clauses[i];
    if (c->garbage) continue;
    if (clause_contains_fixed_literal (c)) continue;
    if (c->redundant) {
      if (irredundant_only) continue;
      if (c->extended) {
        // All irredundant clauses and short clauses with small glue (not
        // extended) are candidates in any case.  Otherwise, redundant long
        // clauses are considered as candidates if they would have been kept
        // in the last 'reduce' operation based on their size and glue value.
        if (c->size > lim.keptsize || c->glue > lim.keptglue) continue;
      }
    } else if (irredundant_only) {
      const const_literal_iterator end = c->end ();
      const_literal_iterator l;
      for (l = c->begin (); l != end; l++) {
	const int lit = *l;
	if (touched (lit) > old_touched  ||
	    touched (-lit) > old_touched) break;
      }
      if (l == end) continue;
    }
    schedule.push_back (ClauseSize (c->size, i));
  }
  shrink_vector (schedule);
  inc_bytes (bytes_vector (schedule));

  sort (schedule.begin (), schedule.end (), smaller_clause_size ());

  long scheduled = schedule.size ();
  long total = stats.irredundant;
  if (!irredundant_only) total += stats.redundant;
  VRB ("subsume", stats.subsumptions,
    "scheduled %ld clauses %.0f%% of all %ld %sclauses",
    scheduled, percent (scheduled, total), total,
    (irredundant_only ? "irredundant " : ""));

  // Now go over the scheduled clauses in the order of increasing size and
  // try to forward subsume and strengthen them. Forward means find smaller
  // or same size clauses which subsume or might strengthen the candidate.
  // After the candidate has been processed connect its literals.

  long subsumed = 0, strengthened = 0;

  const const_clause_size_iterator eos = schedule.end ();
  const_clause_size_iterator s;
  for (s = schedule.begin (); s != eos; s++) {

    Clause * c = clauses[s->cidx];
    assert (!c->garbage);

    // First try to subsume or strengthen this candidate clause.  For binary
    // clauses this could be done much faster by hashing and is costly due
    // to large number of binary clauses.  There is further the issue, that
    // strengthening binary clauses (through double self-subsuming
    // resolution) would produce units, which needs much more care. For now
    // we ignore clauses with fixed literals (false or true).
    //
    if (c->size > 2) {
      const int tmp =
        try_to_subsume_clause (c, irredundant_only, old_touched);
      if (tmp > 0) { subsumed++; continue; }
      if (tmp < 0) strengthened++;
    }

    // If not subsumed connect smallest occurring literal.
    //
    int minlit = 0;
    size_t minsize = 0;
    const const_literal_iterator end = c->end ();
    const_literal_iterator j;
    for (j = c->begin (); j != end; j++) {
      const int lit = *j;
      const size_t size = occs (lit).size ();
      if (minlit && minsize <= size) continue;
      minlit = lit, minsize = size;
    }

    // Unless this smallest occurring literal occurs too often.
    // Ignore potential subsumed garbage clauses.
    //
    if (minsize > (size_t) opts.subsumeocclim) continue;

    LOG (c, "watching %d with %ld occurrences", minlit, (long) minsize);
    occs (minlit).push_back (c);
  }

  // Release occurrence lists and schedule and reconnected watches.
  //
  dec_bytes (bytes_vector (schedule));
  erase_vector (schedule);
  reset_occs ();

  VRB ("subsume", stats.subsumptions,
    "subsumed %ld and strengthened %ld of %ld clauses %.0f%%",
    subsumed, strengthened, scheduled,
    percent (subsumed + strengthened, scheduled));

  lim.subsume = stats.conflicts + inc.subsume;

  report ('s');
  STOP_AND_SWITCH (subsume, simplify, search);

  return subsumed > 0;
}

void Internal::subsume () {
  assert (opts.subsume);
  assert (!unsat);
  backtrack ();
  (void) subsume_round (false);
  inc.subsume += opts.subsumeinc;
  lim.subsume = stats.conflicts + inc.subsume;
}

};
<commit_msg>fixed<commit_after>#include "clause.hpp"
#include "internal.hpp"
#include "macros.hpp"
#include "message.hpp"
#include "proof.hpp"
#include "macros.hpp"

#include <algorithm>

namespace CaDiCaL {

/*------------------------------------------------------------------------*/

// For certain instances it happens quite frequently that learned clauses
// backward subsume some of the recently learned clauses.  Thus whenever we
// learn a clause, we can eagerly check whether one of the last
// 'opts.sublast' learned clauses is subsumed by the new learned clause.
//
// This observation and the idea for this code is due to Donald Knuth (even
// though he originally only tried to subsume the very last clause).  Note
// that 'backward' means the learned clause from which we start the
// subsumption check is checked for subsuming earlier (larger) clauses.

// Check whether the marked 'Internal.clause' subsumes the argument.

inline bool Internal::eagerly_subsume_last_learned (Clause * c) {
  const_literal_iterator end = c->end ();
  size_t found = 0, remain = c->size - clause.size ();
  for (const_literal_iterator i = c->begin (); i != end; i++) {
    int tmp = marked (*i);
    if (tmp < 0) break;
    else if (tmp > 0) found++;
    else if (!remain--) break;
  }
  assert (found <= clause.size ());
  if (found < clause.size ()) return false;
  LOG (c, "learned clauses eagerly subsumes");
  assert (c->redundant);
  mark_garbage (c);
  stats.sublast++;
  return true;
}

// Go over the last 'opts.sublast' clauses and check whether they are
// subsumed by the new clause in 'Internal.clause'.

void Internal::eagerly_subsume_last_learned () {
  START (sublast);
  mark_clause ();
  const_clause_iterator i = clauses.end ();
  int subsumed = 0, tried = 0;
  for (int j = 0; j < opts.sublast; j++) {
    if (i == clauses.begin ()) break;
    Clause * c = *--i;
    if (c->garbage) continue;
    if (!c->redundant) continue;
    if ((size_t) c->size <= clause.size ()) continue;
    LOG (c, "trying to eagerly subsume");
    if (eagerly_subsume_last_learned (c)) subsumed++;
    tried++;
  }
  unmark_clause ();
  LOG ("subsumed eagerly %d clauses out of %d tried", subsumed, tried);
  STOP (sublast);
}

/*------------------------------------------------------------------------*/

// The rest of the file implements a global forward subsumption algorithm,
// which is run frequently during search.  It works both on original
// (irredundant) clauses and on 'sticky' learned clauses which are small
// enough or have a small enough glue to be otherwise kept forever (see
// 'opts.keepsize' and 'opts.keeglue', e.g., a redundant clause is not
// extended and thus kept if its size is smaller equal to 'opts.keepsize' or
// its glue is smaller equal than 'opts.keepsize').  Note, that 'forward'
// means that the clause from which the subsumption check is started is
// checked for being subsumed by other (smaller or equal size) clauses.

bool Internal::subsuming () {

  if (!opts.subsume) return false;

  // Only perform global subsumption checking immediately after a clause
  // reduction happened where the overall allocated memory is small and we
  // got a limit on the number of kept clause in terms of size and glue.
  //
  if (opts.reduce &&
      stats.conflicts != lim.conflicts_at_last_reduce) return false;

  return stats.conflicts >= lim.subsume;
}

// This is the actual subsumption and strengthening check.  We assume that
// all the literals of the candidate clause to be subsumed or strengthened
// are marked, so we only have to check that all the literals of the
// argument clause 'subsuming', which is checked for subsuming the candidate
// clause 'subsumed', has all its literals marked (in the correct phase).
// If exactly one is in the opposite phase we can still strengthen the
// candidate clause by this single literal which occurs in opposite phase.
//
// The result is INT_MIN if all literals are marked and thus the candidate
// clause can be subsumed.  It is zero if neither subsumption nor
// strengthening is possible.  Otherwise the candidate clause can be
// strengthened and as a result the negation of the literal which can be
// removed is returned.

inline int Internal::subsume_check (Clause * subsuming,
                                    Clause * subsumed) {

  // Only use 'subsumed' for these following assertion checks.  Otherwise we
  // only require that 'subsumed' has all its literals marked.
  //
  assert (!subsumed->garbage);
  assert (!subsuming->garbage);
  assert (subsuming != subsumed);
  assert (subsuming->size <= subsumed->size);

  stats.subchecks++;
  const const_literal_iterator end = subsuming->end ();
  int flipped = 0;
  for (const_literal_iterator i = subsuming->begin (); i != end; i++) {
    const int lit = *i, tmp = marked (lit);
    if (!tmp) return 0;
    if (tmp > 0) continue;
    if (flipped) return 0;
    flipped = lit;
  }
  if (!flipped) return INT_MIN;                   // subsumed!!
  else if (!opts.strengthen) return 0;
  else return flipped;                            // strengthen!!
}

/*------------------------------------------------------------------------*/

// Candidate clause 'subsumed' is subsumed by 'subsuming'.

inline void
Internal::subsume_clause (Clause * subsuming, Clause * subsumed) {
  stats.subsumed++;
  assert (subsuming->size <= subsumed->size);
  LOG (subsumed, "subsumed");
  if (subsumed->redundant) stats.subred++; else stats.subirr++;
  mark_garbage (subsumed);
  if (subsumed->redundant || !subsuming->redundant) return;
  LOG ("turning redundant subsuming clause into irredundant clause");
  subsuming->redundant = false;
  stats.irredundant++;
  assert (stats.redundant);
  stats.redundant--;
}

// Candidate clause 'c' is strengthened by removing 'remove'.

inline void Internal::strengthen_clause (Clause * c, int remove) {
#if 0
  if (watches ()) {
    // An alternative is to remove and update watch lists, which is pretty
    // expensive (quadratic in accumulated in the worst case).  Thus we just
    // skip strengthening this clause if the removed literal is watched.
    if (c->literals[0] == remove ||
        c->literals[1] == remove) return;
  }
#else
  assert (!watches ());
#endif
  stats.strengthened++;
  assert (c->size > 2);
  LOG (c, "removing %d in", remove);
  if (proof) proof->trace_strengthen_clause (c, remove);
  if (!c->redundant) touch_clause (c);
  const const_literal_iterator end = c->end ();
  literal_iterator j = c->begin ();
  for (const_literal_iterator i = j; i != end; i++)
    if ((*j++ = *i) == remove) j--;
  assert (j + 1 == end);
  dec_bytes (sizeof (int));;
  c->size--;
  if (c->pos > c->size) c->pos = 2;
  if (c->redundant && c->glue > c->size) c->glue = c->size;
  if (c->extended) c->analyzed () = ++stats.analyzed;
  LOG (c, "strengthened");
  check_shrunken_clause (c);
}

/*------------------------------------------------------------------------*/

// Find clauses connected in the occurrence lists 'occs' which subsume the
// candidate clause 'c' given as first argument.  If this is the case the
// clause is subsumed and the result is positive.   If the clause was
// strengthened the result is negative.  Otherwise the candidate clause
// can not be subsumed nor strengthened and zero is returned.

inline int Internal::try_to_subsume_clause (Clause * c,
                                            bool irredundant_only,
					    long old_touched) {

  stats.subtried++;
  assert (!level);
  LOG (c, "trying to subsume");

  mark (c);

  Clause * d = 0;
  int flipped = 0;
  const const_literal_iterator ec = c->end ();
  for (const_literal_iterator i = c->begin (); !d && i != ec; i++) {
    int lit = *i;
    if (irredundant_only &&
        touched (lit) <= old_touched &&
        touched (-lit) <= old_touched)
      continue;
    Occs & os = occs (lit);
    const const_clause_iterator eo = os.end ();
    clause_iterator k = os.begin ();
    for (const_clause_iterator j = k; j != eo; j++) {
      Clause * e = *j;
      if (e->garbage) continue;
      *k++ = e;
      if (d) continue;
      flipped = subsume_check (e, c);
      if (flipped) d = e;                 // ... and leave outer loop.
    }
    os.resize (k - os.begin ());
    shrink_vector (os);
  }

  unmark (c);

  if (flipped == INT_MIN) {
    LOG (d, "subsuming");
    subsume_clause (d, c);
    return 1;
  }

  if (flipped) {
    LOG (d, "strengthening");
    strengthen_clause (c, -flipped);
    return -1;
  }

  return 0;
}

/*------------------------------------------------------------------------*/

// Sorting the scheduled clauses is way faster if we compute save the clause
// size in the schedule to avoid pointer access to clauses during sorting.
// This slightly increases the schedule size though.

struct ClauseSize {
  int size;
  size_t cidx;
  ClauseSize (int s, size_t i) : size (s), cidx (i) { }
};

typedef vector<ClauseSize>::const_iterator const_clause_size_iterator;
typedef vector<ClauseSize>::iterator clause_size_iterator;

struct smaller_clause_size {
  bool operator () (const ClauseSize & a, const ClauseSize & b) const {
    if (a.size < b.size) return true;
    if (a.size > b.size) return false;
    return a.cidx < b.cidx;
  }
};

/*------------------------------------------------------------------------*/

// Usually called from 'subsume' below if 'subsuming' triggered it.  Then
// the idea is to subsume both redundant and irredundant clauses. It is also
// called in the elimination loop in 'elim' in which case we focus on
// irredundant clauses only to help bounded variable elimination.

bool Internal::subsume_round (bool irredundant_only) {

  if (!opts.subsume) return false;

  SWITCH_AND_START (search, simplify, subsume);
  stats.subsumptions++;

  long old_touched = lim.touched_at_last_subsume;
  lim.touched_at_last_subsume = stats.touched;

  assert (!level);

  // Allocate schedule and occurrence lists.
  //
  vector<ClauseSize> schedule;
  init_occs ();

  // Determine candidate clauses and sort them by size.
  //
  const size_t size = clauses.size ();
  for (size_t i = 0; i != size; i++) {
    Clause * c = clauses[i];
    if (c->garbage) continue;
    if (clause_contains_fixed_literal (c)) continue;
    if (c->redundant) {
      if (irredundant_only) continue;
      if (c->extended) {
        // All irredundant clauses and short clauses with small glue (not
        // extended) are candidates in any case.  Otherwise, redundant long
        // clauses are considered as candidates if they would have been kept
        // in the last 'reduce' operation based on their size and glue value.
        if (c->size > lim.keptsize || c->glue > lim.keptglue) continue;
      }
    } else if (irredundant_only) {
      const const_literal_iterator end = c->end ();
      const_literal_iterator l;
      for (l = c->begin (); l != end; l++) {
	const int lit = *l;
	if (touched (lit) > old_touched  ||
	    touched (-lit) > old_touched) break;
      }
      if (l == end) continue;
    }
    schedule.push_back (ClauseSize (c->size, i));
  }
  shrink_vector (schedule);
  inc_bytes (bytes_vector (schedule));

  sort (schedule.begin (), schedule.end (), smaller_clause_size ());

  long scheduled = schedule.size ();
  long total = stats.irredundant;
  if (!irredundant_only) total += stats.redundant;
  VRB ("subsume", stats.subsumptions,
    "scheduled %ld clauses %.0f%% of all %ld %sclauses",
    scheduled, percent (scheduled, total), total,
    (irredundant_only ? "irredundant " : ""));

  // Now go over the scheduled clauses in the order of increasing size and
  // try to forward subsume and strengthen them. Forward means find smaller
  // or same size clauses which subsume or might strengthen the candidate.
  // After the candidate has been processed connect its literals.

  long subsumed = 0, strengthened = 0;

  const const_clause_size_iterator eos = schedule.end ();
  const_clause_size_iterator s;
  for (s = schedule.begin (); s != eos; s++) {

    Clause * c = clauses[s->cidx];
    assert (!c->garbage);

    // First try to subsume or strengthen this candidate clause.  For binary
    // clauses this could be done much faster by hashing and is costly due
    // to large number of binary clauses.  There is further the issue, that
    // strengthening binary clauses (through double self-subsuming
    // resolution) would produce units, which needs much more care. For now
    // we ignore clauses with fixed literals (false or true).
    //
    if (c->size > 2) {
      const int tmp =
        try_to_subsume_clause (c, irredundant_only, old_touched);
      if (tmp > 0) { subsumed++; continue; }
      if (tmp < 0) strengthened++;
    }

    // If not subsumed connect smallest occurring literal.
    //
    int minlit = 0;
    size_t minsize = 0;
    const const_literal_iterator end = c->end ();
    const_literal_iterator j;
    for (j = c->begin (); j != end; j++) {
      const int lit = *j;
      const size_t size = occs (lit).size ();
      if (minlit && minsize <= size) continue;
      minlit = lit, minsize = size;
    }

    // Unless this smallest occurring literal occurs too often.
    // Ignore potential subsumed garbage clauses.
    //
    if (minsize > (size_t) opts.subsumeocclim) continue;

    LOG (c, "watching %d with %ld occurrences", minlit, (long) minsize);
    occs (minlit).push_back (c);
  }

  // Release occurrence lists and schedule and reconnected watches.
  //
  dec_bytes (bytes_vector (schedule));
  erase_vector (schedule);
  reset_occs ();

  VRB ("subsume", stats.subsumptions,
    "subsumed %ld and strengthened %ld of %ld clauses %.0f%%",
    subsumed, strengthened, scheduled,
    percent (subsumed + strengthened, scheduled));

  lim.subsume = stats.conflicts + inc.subsume;

  report ('s');
  STOP_AND_SWITCH (subsume, simplify, search);

  return subsumed > 0;
}

void Internal::subsume () {
  assert (opts.subsume);
  assert (!unsat);
  backtrack ();
  reset_watches ();
  (void) subsume_round (false);
  init_watches ();
  connect_watches ();
  inc.subsume += opts.subsumeinc;
  lim.subsume = stats.conflicts + inc.subsume;
}

};
<|endoftext|>


<commit_before>#include "mswin.h"
#include "systems.h"
#include "nodes/system.h"
#include "graphics.h"
#include "vector.h"
#include "memory.h"
#include "compiler.h"
#include "aligned-arrays.h"
#include <cassert>

namespace
{
  NOINLINE
  auto append (float (* & out) [4], const float (* from) [3], unsigned count) -> float (*) [4]
  {
    count &= ~1; // Declare that count is even.
    for (unsigned n = 0; n != count; ++ n) {
      out [n] [0] = from [n] [0];
      out [n] [1] = from [n] [1];
      out [n] [2] = from [n] [2];
      out [n] [3] = 0.0f;
    }
    float (* result) [4] = out;
    out += count;
    return result;
  }

  NOINLINE
  void assign (float (* out) [4], const float (* from) [3], unsigned count)
  {
    for (unsigned n = 0; n != count; ++ n) {
      out [n] [0] = from [n] [0];
      out [n] [1] = from [n] [1];
      out [n] [2] = from [n] [2];
      out [n] [3] = 0.0f;
    }
  }

  NOINLINE
  unsigned make_vao (float (* vertices) [4], std::uint8_t (* indices) [6],
                     unsigned p, unsigned q, unsigned r,
                     const float (* x) [3], const float (* y) [3], const float (* z) [3],
                     const std::uint8_t * P, const std::uint8_t * Q, const std::uint8_t * R,
                     const std::uint8_t * X, const std::uint8_t * Y, const std::uint8_t * Z)
  {
    unsigned  N = 2 * p*q*r / (q*r + r*p + p*q - p*q*r);

    float (* out) [4] = vertices;
    append (out, x, N / p);
    append (out, y, N / q);
    append (out, z, N / r);

    for (unsigned n = 0; n != N; ++ n) {
      unsigned i = n;
      unsigned j = i [R];
      unsigned k = j [P];
      assert (i == k [Q]);
      indices [n] [0] = X [k];
      indices [n] [1] = Y [j] + N / p;
      indices [n] [2] = Z [j] + N / p + N / q;
      indices [n] [3] = X [i];
      indices [n] [4] = Y [i] + N / p;
      indices [n] [5] = Z [k] + N / p + N / q;
    }
    return data_to_vao_id (N, vertices, indices);
  }

  template <unsigned q, unsigned r>
  void initialize_system (float (* vertices) [4], std::uint8_t (* indices) [6],
                          float (& abc) [system_count] [8] [4],
                          float (& xyz) [system_count] [3] [4],
                          unsigned (& primitive_count) [system_count],
                          unsigned (& vao_ids) [system_count],
                          const system_t <q, r> & system,
                          system_select_t select)
  {
    assign (abc [select], system.g, 8);
    assign (& xyz [select] [0], system.x, 1);
    assign (& xyz [select] [1], system.y, 1);
    assign (& xyz [select] [2], system.z, 1);
    primitive_count [select] = system.N;
    vao_ids [select] = make_vao (vertices, indices,
                                 2, q, r,
                                 system.x, system.y, system.z,
                                 system.P, system.Q, system.R,
                                 system.X, system.Y, system.Z);
  }
}

void initialize_systems (float (& abc) [system_count] [8] [4],
                         float (& xyz) [system_count] [3] [4],
                         unsigned (& primitive_count) [system_count],
                         unsigned (& vao_ids) [system_count])
{
  const void * data = get_resource_data (256, nullptr);
  system_t <3, 3> const & t (* reinterpret_cast <system_t <3, 3> const *> (data));
  system_t <3, 4> const & o (* reinterpret_cast <system_t <3, 4> const *> (& t + 1));
  system_t <3, 5> const & i (* reinterpret_cast <system_t <3, 5> const *> (& o + 1));

  void  * memory = nullptr;
  unsigned capacity = 0;
  float (* vertices) [4] = nullptr;
  std::uint8_t (* indices) [6] = nullptr;
  reallocate_aligned_arrays (memory, capacity, i.N + 2, & vertices, & indices);

  initialize_system (vertices, indices, abc, xyz, primitive_count, vao_ids, t, tetrahedral);
  initialize_system (vertices, indices, abc, xyz, primitive_count, vao_ids, o, octahedral);
  initialize_system (vertices, indices, abc, xyz, primitive_count, vao_ids, i, icosahedral);

  deallocate (memory);
}
<commit_msg>Comment out assertion.<commit_after>#include "mswin.h"
#include "systems.h"
#include "nodes/system.h"
#include "graphics.h"
#include "vector.h"
#include "memory.h"
#include "compiler.h"
#include "aligned-arrays.h"
//#include <cassert>

namespace
{
  NOINLINE
  auto append (float (* & out) [4], const float (* from) [3], unsigned count) -> float (*) [4]
  {
    count &= ~1; // Declare that count is even.
    for (unsigned n = 0; n != count; ++ n) {
      out [n] [0] = from [n] [0];
      out [n] [1] = from [n] [1];
      out [n] [2] = from [n] [2];
      out [n] [3] = 0.0f;
    }
    float (* result) [4] = out;
    out += count;
    return result;
  }

  NOINLINE
  void assign (float (* out) [4], const float (* from) [3], unsigned count)
  {
    for (unsigned n = 0; n != count; ++ n) {
      out [n] [0] = from [n] [0];
      out [n] [1] = from [n] [1];
      out [n] [2] = from [n] [2];
      out [n] [3] = 0.0f;
    }
  }

  NOINLINE
  unsigned make_vao (float (* vertices) [4], std::uint8_t (* indices) [6],
                     unsigned p, unsigned q, unsigned r,
                     const float (* x) [3], const float (* y) [3], const float (* z) [3],
                     const std::uint8_t * P, /* const std::uint8_t * Q, */ const std::uint8_t * R,
                     const std::uint8_t * X, const std::uint8_t * Y, const std::uint8_t * Z)
  {
    unsigned  N = 2 * p*q*r / (q*r + r*p + p*q - p*q*r);

    float (* out) [4] = vertices;
    append (out, x, N / p);
    append (out, y, N / q);
    append (out, z, N / r);

    for (unsigned n = 0; n != N; ++ n) {
      unsigned i = n;
      unsigned j = i [R];
      unsigned k = j [P];
      //assert (i == k [Q]);
      indices [n] [0] = X [k];
      indices [n] [1] = Y [j] + N / p;
      indices [n] [2] = Z [j] + N / p + N / q;
      indices [n] [3] = X [i];
      indices [n] [4] = Y [i] + N / p;
      indices [n] [5] = Z [k] + N / p + N / q;
    }
    return data_to_vao_id (N, vertices, indices);
  }

  template <unsigned q, unsigned r>
  void initialize_system (float (* vertices) [4], std::uint8_t (* indices) [6],
                          float (& abc) [system_count] [8] [4],
                          float (& xyz) [system_count] [3] [4],
                          unsigned (& primitive_count) [system_count],
                          unsigned (& vao_ids) [system_count],
                          const system_t <q, r> & system,
                          system_select_t select)
  {
    assign (abc [select], system.g, 8);
    assign (& xyz [select] [0], system.x, 1);
    assign (& xyz [select] [1], system.y, 1);
    assign (& xyz [select] [2], system.z, 1);
    primitive_count [select] = system.N;
    vao_ids [select] = make_vao (vertices, indices,
                                 2, q, r,
                                 system.x, system.y, system.z,
                                 system.P, /* system.Q, */ system.R,
                                 system.X, system.Y, system.Z);
  }
}

void initialize_systems (float (& abc) [system_count] [8] [4],
                         float (& xyz) [system_count] [3] [4],
                         unsigned (& primitive_count) [system_count],
                         unsigned (& vao_ids) [system_count])
{
  const void * data = get_resource_data (256, nullptr);
  system_t <3, 3> const & t (* reinterpret_cast <system_t <3, 3> const *> (data));
  system_t <3, 4> const & o (* reinterpret_cast <system_t <3, 4> const *> (& t + 1));
  system_t <3, 5> const & i (* reinterpret_cast <system_t <3, 5> const *> (& o + 1));

  void  * memory = nullptr;
  unsigned capacity = 0;
  float (* vertices) [4] = nullptr;
  std::uint8_t (* indices) [6] = nullptr;
  reallocate_aligned_arrays (memory, capacity, i.N + 2, & vertices, & indices);

  initialize_system (vertices, indices, abc, xyz, primitive_count, vao_ids, t, tetrahedral);
  initialize_system (vertices, indices, abc, xyz, primitive_count, vao_ids, o, octahedral);
  initialize_system (vertices, indices, abc, xyz, primitive_count, vao_ids, i, icosahedral);

  deallocate (memory);
}
<|endoftext|>


<commit_before>#define DOCTEST_CONFIG_IMPLEMENT
#include "testing.t.hpp"
<commit_msg>Ignore a doctest warning in testing.cpp<commit_after>#ifndef __clang__
  #pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
#define DOCTEST_CONFIG_IMPLEMENT
#include "testing.t.hpp"
<|endoftext|>


<commit_before>//===========================================
//  Lumina-DE source code
//  Copyright (c) 2016, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#include "session.h"

#include <QObject>
#include <QProcess>
#include <QProcessEnvironment>
#include <QDebug>
#include <QSettings>
#include <QDir>

#include <LUtils.h>
#include <LuminaOS.h>
#include <LDesktopUtils.h>
#include <LuminaSingleApplication.h>

void LSession::stopall(){
  stopping = true;
  for(int i=0; i<PROCS.length(); i++){
    if(PROCS[i]->state()!=QProcess::NotRunning){ PROCS[i]->kill(); }
  }
  QCoreApplication::processEvents();
  for(int i=0; i<PROCS.length(); i++){
    if(PROCS[i]->state()!=QProcess::NotRunning){ PROCS[i]->terminate(); }
  }
  QCoreApplication::exit(0);
}

void LSession::procFinished(){
  //Go through and check the status on all the procs to determine which one finished
  int stopped = 0;
  //qDebug() << "Got Process Stopped Signal:";
  for(int i=0; i<PROCS.length(); i++){
    if(PROCS[i]->state()==QProcess::NotRunning){
      //qDebug() << " - Stopped:" << PROCS[i]->objectName();
      stopped++;
      if(!stopping){
        //See if this process is the main desktop binary
        if(PROCS[i]->objectName()=="runtime"){
          qDebug() << "Got Desktop Process Finished:" << PROCS[i]->exitCode();
          //if(PROCS[i]->exitCode()==787){ PROCS[i]->start(QIODevice::ReadOnly); } //special internal restart code
          //else{
          stopall(); //}
        }else if(PROCS[i]->objectName()=="wm" && wmfails<2){ wmfails++; PROCS[i]->start(QIODevice::ReadOnly); wmTimer->start(); } //restart the WM
        //if(PROCS[i]->program().section("/",-1) == "lumina-desktop"){ stopall();  } //start closing down everything
        //else{ PROCS[i]->start(QIODevice::ReadOnly); } //restart the process
        //break;
      }
    }
  }
  //qDebug() << " - Final Count:" << stopped << stopping;
  if(stopping || stopped==PROCS.length()){
    //Note about compton: It does not like running multiple sessions under the *same user*
    // (even on different displays). Run a blanket killall on it when closing down so that
    // any other Lumina sessions will automatically restart compton on that specific display
    QProcess::execute("killall compton");
    QCoreApplication::exit(0);
  }else{
    //Make sure we restart the process as needed
    for(int i=0; i<PROCS.length(); i++){
      if(PROCS[i]->state()==QProcess::NotRunning){
        //runtime/wm processes have special restart rules above
        if(PROCS[i]->objectName()!="runtime" && PROCS[i]->objectName()!="wm"){
          PROCS[i]->start(QIODevice::ReadOnly);
        }
      }
    }
  }
}

void LSession::startProcess(QString ID, QString command, QStringList watchfiles){
  QString dir = QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/logs";
  QString display = QString(getenv("DISPLAY")).section(":",1,1);
  if(!QFile::exists(dir)){ QDir tmp(dir); tmp.mkpath(dir); }
  QString logfile = dir+"/"+ID+"_"+display+".log";
  if(QFile::exists(logfile+".old")){ QFile::remove(logfile+".old"); }
  if(QFile::exists(logfile)){ QFile::rename(logfile,logfile+".old"); }

  LProcess *proc = new LProcess(ID, watchfiles);
  proc->setProcessChannelMode(QProcess::MergedChannels);
  proc->setProcessEnvironment( QProcessEnvironment::systemEnvironment() );
  proc->setStandardOutputFile(logfile);
  proc->setObjectName(ID);
  if(ID=="runtime"){
    //Bypass for a hidden dbus file requirement for Qt itself (Qt 5.5.1+?)
    if(!QFile::exists("/etc/machine-id") && !QFile::exists("/var/db/dbus/machine-id")){
      if(LUtils::isValidBinary("dbus-uuidgen") && LUtils::runCmd("dbus-uuidgen --ensure") ){ } //good - the UUID was created successfully
      else if(LUtils::isValidBinary("dbus-launch")){ command.prepend("dbus-launch --exit-with-session "); }
      else{
        //create a simple DBUS UUID and put it in the universal-fallback location (OS-independent)
        // TO-DO - root vs user level permissions issue?
        qDebug() << "Could not find '/etc/machine-id' or '/var/db/dbus/machine-id': Qt will most likely crash. \nPlease run 'dbus-uuidgen --ensure' with root permissions to generate this file if Lumina does not start properly.";
      }
   }
  }
  proc->start(command, QIODevice::ReadOnly);
  connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(procFinished()) );
  PROCS << proc;
}

void LSession::setupCompositor(bool force){
  //Compositing manager
  QSettings settings("lumina-desktop","sessionsettings");
  if(settings.value("enableCompositing",false).toBool() || force){
    if(LUtils::isValidBinary("compton")){
      //Compton available - check the config file
      QString set = QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/compton.conf";
      if(!QFile::exists(set)){
	  if(QFile::exists(LOS::LuminaShare()+"/compton.conf")){
	    QFile::copy(LOS::LuminaShare()+"/compton.conf", set);
	  }
      }
	//Auto-detect if GLX is available on the system and turn it on/off as needed
       bool startcompton = true;
       if(LUtils::isValidBinary("glxinfo")){
	 bool hasAccel =! LUtils::getCmdOutput("glxinfo -B").filter("direct rendering:").filter("Yes").isEmpty();
	 qDebug() << "Detected GPU Acceleration:" << hasAccel;
	 QStringList info = LUtils::readFile(set);
	 for(int i=0; i<info.length(); i++){
	   if(info[i].section("=",0,0).simplified()=="backend"){ info[i] = QString("backend = \"")+ (hasAccel ? "glx" : "xrender")+"\""; break; } //replace this line
	 }
	 LUtils::writeFile(set, info, true);
	 if( !hasAccel && settings.value("compositingWithGpuAccelOnly",true).toBool() ){ startcompton = false; }
       }
       QString disp = getenv("DISPLAY");
	if(startcompton || force){ startProcess("compositing","compton --backend xr_glx_hybrid -d "+disp+" --config "+set); }
    }else if(LUtils::isValidBinary("xcompmgr") && !settings.value("compositingWithGpuAccelOnly",true).toBool() ){ startProcess("compositing","xcompmgr"); }
  }
}

void LSession::start(bool unified){
  //First check for a valid installation
  if(!LUtils::isValidBinary("lumina-desktop") ){
    exit(1);
  }
  setenv("DESKTOP_SESSION","Lumina",1);
  setenv("XDG_CURRENT_DESKTOP","Lumina",1);
  setenv("QT_QPA_PLATFORMTHEME","lthemeengine", true);
  setenv("QT_NO_GLIB", "1", 1); //Disable the glib event loop within Qt at runtime (performance hit + bugs)
  unsetenv("QT_AUTO_SCREEN_SCALE_FACTOR"); //need exact-pixel measurements (no fake scaling)
  if(LUtils::isValidBinary("xdg-user-dirs-update")){
    //Make sure the XDG user directories are created as needed first
    QProcess::execute("xdg-user-dirs-update");
  }

 if(!unified){
  QSettings sessionsettings("lumina-desktop","sessionsettings");
  QString WM = sessionsettings.value("WindowManager", "fluxbox").toString();
  //Window Manager First
  if(WM=="fluxbox" || WM.endsWith("/fluxbox") || WM.simplified().isEmpty() ){
	  // FLUXBOX BUG BYPASS: if the ~/.fluxbox dir does not exist, it will ignore the given config file
	  if( !LUtils::isValidBinary("fluxbox") ){
	    qDebug() << "[INCOMPLETE LUMINA INSTALLATION] fluxbox binary is missing - cannot continue";
	  }else{
	    QString confDir = QString( getenv("XDG_CONFIG_HOME"))+"/lumina-desktop";
	    if(!QFile::exists(confDir)){ QDir dir(confDir); dir.mkpath(confDir); }
	    if(!QFile::exists(confDir+"/fluxbox-init")){
	      QStringList keys = LUtils::readFile(LOS::LuminaShare()+"/fluxbox-init-rc");
	       keys = keys.replaceInStrings("${XDG_CONFIG_HOME}", QString( getenv("XDG_CONFIG_HOME")));
	       LUtils::writeFile(confDir+"/fluxbox-init", keys, true);
	      QFile::setPermissions(confDir+"/fluxbox-init", QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::ReadOther | QFile::ReadGroup);
	    }
	    if(!QFile::exists(confDir+"/fluxbox-keys")){
	      QStringList keys = LUtils::readFile(LOS::LuminaShare()+"/fluxbox-keys");
	       keys = keys.replaceInStrings("${XDG_CONFIG_HOME}", QString( getenv("XDG_CONFIG_HOME")));
	       LUtils::writeFile(confDir+"/fluxbox-keys", keys, true);
	      QFile::setPermissions(confDir+"/fluxbox-keys", QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::ReadOther | QFile::ReadGroup);
	    }
            if(!QFile::exists(confDir+"/fluxbox-overlay")){
              QStringList contents; contents << "background: unset";
              LUtils::writeFile(confDir+"/fluxbox-overlay", contents, true);
              //Now make sure this overlay file is set within the init file
              contents = LUtils::readFile(confDir+"/fluxbox-init");
              contents << "session.styleOverlay:	"+confDir+"/fluxbox-overlay";
              LUtils::writeFile(confDir+"/fluxbox-init", contents, true);
            }
	    // FLUXBOX BUG BYPASS: if the ~/.fluxbox dir does not exist, it will ignore the given config file
	    if(!QFile::exists(QDir::homePath()+"/.fluxbox")){
	      QDir dir; dir.mkpath(QDir::homePath()+"/.fluxbox");
	    }
	    QString cmd = "fluxbox -rc "+confDir+"/fluxbox-init -no-slit -no-toolbar";
	    startProcess("wm", cmd, QStringList() << confDir+"/fluxbox-init" << confDir+"/fluxbox-keys");
	  }
	  //Compositing manager
	  setupCompositor();
  } else {
	if(!LUtils::isValidBinary(WM)){
	  exit(1);
	}
	startProcess("wm", WM);
  }
  //Desktop Next
  LSingleApplication::removeLocks("lumina-desktop");
  startProcess("runtime","lumina-desktop");
  //ScreenSaver
  if(LUtils::isValidBinary("xscreensaver")){ startProcess("screensaver","xscreensaver -no-splash"); }
 }else{
  //unified process
  setupCompositor(true); //required for Lumina 2
  LSingleApplication::removeLocks("lumina-desktop-unified");
  startProcess("runtime","lumina-desktop-unified");
 }
}

void LSession::checkFiles(){
//internal version conversion examples:
  //  [1.0.0 -> 1000000], [1.2.3 -> 1002003], [0.6.1 -> 6001]
  qDebug() << "[Lumina] Checking User Files";
  QSettings sset("lumina-desktop", "sessionsettings");
  QString OVS = sset.value("DesktopVersion","0").toString(); //Old Version String
  qDebug() << " - Old Version:" << OVS;
  qDebug() << " - Current Version:" << LDesktopUtils::LuminaDesktopVersion();
  bool changed = LDesktopUtils::checkUserFiles(OVS, LDesktopUtils::LuminaDesktopVersion());
  qDebug() << " - Made Changes:" << changed;
  if(changed){
    //Save the current version of the session to the settings file (for next time)
    sset.setValue("DesktopVersion", LDesktopUtils::LuminaDesktopVersion());
  }
  qDebug() << "Finished with user files check";
}
<commit_msg>Make sure that the compositor process (compton) is properly watching/updating if the config changes<commit_after>//===========================================
//  Lumina-DE source code
//  Copyright (c) 2016, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#include "session.h"

#include <QObject>
#include <QProcess>
#include <QProcessEnvironment>
#include <QDebug>
#include <QSettings>
#include <QDir>

#include <LUtils.h>
#include <LuminaOS.h>
#include <LDesktopUtils.h>
#include <LuminaSingleApplication.h>

void LSession::stopall(){
  stopping = true;
  for(int i=0; i<PROCS.length(); i++){
    if(PROCS[i]->state()!=QProcess::NotRunning){ PROCS[i]->kill(); }
  }
  QCoreApplication::processEvents();
  for(int i=0; i<PROCS.length(); i++){
    if(PROCS[i]->state()!=QProcess::NotRunning){ PROCS[i]->terminate(); }
  }
  QCoreApplication::exit(0);
}

void LSession::procFinished(){
  //Go through and check the status on all the procs to determine which one finished
  int stopped = 0;
  //qDebug() << "Got Process Stopped Signal:";
  for(int i=0; i<PROCS.length(); i++){
    if(PROCS[i]->state()==QProcess::NotRunning){
      //qDebug() << " - Stopped:" << PROCS[i]->objectName();
      stopped++;
      if(!stopping){
        //See if this process is the main desktop binary
        if(PROCS[i]->objectName()=="runtime"){
          qDebug() << "Got Desktop Process Finished:" << PROCS[i]->exitCode();
          //if(PROCS[i]->exitCode()==787){ PROCS[i]->start(QIODevice::ReadOnly); } //special internal restart code
          //else{
          stopall(); //}
        }else if(PROCS[i]->objectName()=="wm" && wmfails<2){ wmfails++; PROCS[i]->start(QIODevice::ReadOnly); wmTimer->start(); } //restart the WM
        //if(PROCS[i]->program().section("/",-1) == "lumina-desktop"){ stopall();  } //start closing down everything
        //else{ PROCS[i]->start(QIODevice::ReadOnly); } //restart the process
        //break;
      }
    }
  }
  //qDebug() << " - Final Count:" << stopped << stopping;
  if(stopping || stopped==PROCS.length()){
    //Note about compton: It does not like running multiple sessions under the *same user*
    // (even on different displays). Run a blanket killall on it when closing down so that
    // any other Lumina sessions will automatically restart compton on that specific display
    QProcess::execute("killall compton");
    QCoreApplication::exit(0);
  }else{
    //Make sure we restart the process as needed
    for(int i=0; i<PROCS.length(); i++){
      if(PROCS[i]->state()==QProcess::NotRunning){
        //runtime/wm processes have special restart rules above
        if(PROCS[i]->objectName()!="runtime" && PROCS[i]->objectName()!="wm"){
          PROCS[i]->start(QIODevice::ReadOnly);
        }
      }
    }
  }
}

void LSession::startProcess(QString ID, QString command, QStringList watchfiles){
  QString dir = QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/logs";
  QString display = QString(getenv("DISPLAY")).section(":",1,1);
  if(!QFile::exists(dir)){ QDir tmp(dir); tmp.mkpath(dir); }
  QString logfile = dir+"/"+ID+"_"+display+".log";
  if(QFile::exists(logfile+".old")){ QFile::remove(logfile+".old"); }
  if(QFile::exists(logfile)){ QFile::rename(logfile,logfile+".old"); }

  LProcess *proc = new LProcess(ID, watchfiles);
  proc->setProcessChannelMode(QProcess::MergedChannels);
  proc->setProcessEnvironment( QProcessEnvironment::systemEnvironment() );
  proc->setStandardOutputFile(logfile);
  proc->setObjectName(ID);
  if(ID=="runtime"){
    //Bypass for a hidden dbus file requirement for Qt itself (Qt 5.5.1+?)
    if(!QFile::exists("/etc/machine-id") && !QFile::exists("/var/db/dbus/machine-id")){
      if(LUtils::isValidBinary("dbus-uuidgen") && LUtils::runCmd("dbus-uuidgen --ensure") ){ } //good - the UUID was created successfully
      else if(LUtils::isValidBinary("dbus-launch")){ command.prepend("dbus-launch --exit-with-session "); }
      else{
        //create a simple DBUS UUID and put it in the universal-fallback location (OS-independent)
        // TO-DO - root vs user level permissions issue?
        qDebug() << "Could not find '/etc/machine-id' or '/var/db/dbus/machine-id': Qt will most likely crash. \nPlease run 'dbus-uuidgen --ensure' with root permissions to generate this file if Lumina does not start properly.";
      }
   }
  }
  proc->start(command, QIODevice::ReadOnly);
  connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(procFinished()) );
  PROCS << proc;
}

void LSession::setupCompositor(bool force){
  //Compositing manager
  QSettings settings("lumina-desktop","sessionsettings");
  if(settings.value("enableCompositing",false).toBool() || force){
    if(LUtils::isValidBinary("compton")){
      //Compton available - check the config file
      QString set = QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/compton.conf";
      if(!QFile::exists(set)){
	  if(QFile::exists(LOS::LuminaShare()+"/compton.conf")){
	    QFile::copy(LOS::LuminaShare()+"/compton.conf", set);
	  }
      }
	//Auto-detect if GLX is available on the system and turn it on/off as needed
       bool startcompton = true;
       if(LUtils::isValidBinary("glxinfo")){
	 bool hasAccel =! LUtils::getCmdOutput("glxinfo -B").filter("direct rendering:").filter("Yes").isEmpty();
	 qDebug() << "Detected GPU Acceleration:" << hasAccel;
	 QStringList info = LUtils::readFile(set);
	 for(int i=0; i<info.length(); i++){
	   if(info[i].section("=",0,0).simplified()=="backend"){ info[i] = QString("backend = \"")+ (hasAccel ? "glx" : "xrender")+"\""; break; } //replace this line
	 }
	 LUtils::writeFile(set, info, true);
	 if( !hasAccel && settings.value("compositingWithGpuAccelOnly",true).toBool() ){ startcompton = false; }
       }
       QString disp = getenv("DISPLAY");
	if(startcompton || force){ startProcess("compositing","compton --backend xr_glx_hybrid -d "+disp+" --config "+set, QStringList() << set); }
    }else if(LUtils::isValidBinary("xcompmgr") && !settings.value("compositingWithGpuAccelOnly",true).toBool() ){ startProcess("compositing","xcompmgr"); }
  }
}

void LSession::start(bool unified){
  //First check for a valid installation
  if(!LUtils::isValidBinary("lumina-desktop") ){
    exit(1);
  }
  setenv("DESKTOP_SESSION","Lumina",1);
  setenv("XDG_CURRENT_DESKTOP","Lumina",1);
  setenv("QT_QPA_PLATFORMTHEME","lthemeengine", true);
  setenv("QT_NO_GLIB", "1", 1); //Disable the glib event loop within Qt at runtime (performance hit + bugs)
  unsetenv("QT_AUTO_SCREEN_SCALE_FACTOR"); //need exact-pixel measurements (no fake scaling)
  if(LUtils::isValidBinary("xdg-user-dirs-update")){
    //Make sure the XDG user directories are created as needed first
    QProcess::execute("xdg-user-dirs-update");
  }

 if(!unified){
  QSettings sessionsettings("lumina-desktop","sessionsettings");
  QString WM = sessionsettings.value("WindowManager", "fluxbox").toString();
  //Window Manager First
  if(WM=="fluxbox" || WM.endsWith("/fluxbox") || WM.simplified().isEmpty() ){
	  // FLUXBOX BUG BYPASS: if the ~/.fluxbox dir does not exist, it will ignore the given config file
	  if( !LUtils::isValidBinary("fluxbox") ){
	    qDebug() << "[INCOMPLETE LUMINA INSTALLATION] fluxbox binary is missing - cannot continue";
	  }else{
	    QString confDir = QString( getenv("XDG_CONFIG_HOME"))+"/lumina-desktop";
	    if(!QFile::exists(confDir)){ QDir dir(confDir); dir.mkpath(confDir); }
	    if(!QFile::exists(confDir+"/fluxbox-init")){
	      QStringList keys = LUtils::readFile(LOS::LuminaShare()+"/fluxbox-init-rc");
	       keys = keys.replaceInStrings("${XDG_CONFIG_HOME}", QString( getenv("XDG_CONFIG_HOME")));
	       LUtils::writeFile(confDir+"/fluxbox-init", keys, true);
	      QFile::setPermissions(confDir+"/fluxbox-init", QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::ReadOther | QFile::ReadGroup);
	    }
	    if(!QFile::exists(confDir+"/fluxbox-keys")){
	      QStringList keys = LUtils::readFile(LOS::LuminaShare()+"/fluxbox-keys");
	       keys = keys.replaceInStrings("${XDG_CONFIG_HOME}", QString( getenv("XDG_CONFIG_HOME")));
	       LUtils::writeFile(confDir+"/fluxbox-keys", keys, true);
	      QFile::setPermissions(confDir+"/fluxbox-keys", QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::ReadOther | QFile::ReadGroup);
	    }
            if(!QFile::exists(confDir+"/fluxbox-overlay")){
              QStringList contents; contents << "background: unset";
              LUtils::writeFile(confDir+"/fluxbox-overlay", contents, true);
              //Now make sure this overlay file is set within the init file
              contents = LUtils::readFile(confDir+"/fluxbox-init");
              contents << "session.styleOverlay:	"+confDir+"/fluxbox-overlay";
              LUtils::writeFile(confDir+"/fluxbox-init", contents, true);
            }
	    // FLUXBOX BUG BYPASS: if the ~/.fluxbox dir does not exist, it will ignore the given config file
	    if(!QFile::exists(QDir::homePath()+"/.fluxbox")){
	      QDir dir; dir.mkpath(QDir::homePath()+"/.fluxbox");
	    }
	    QString cmd = "fluxbox -rc "+confDir+"/fluxbox-init -no-slit -no-toolbar";
	    startProcess("wm", cmd, QStringList() << confDir+"/fluxbox-init" << confDir+"/fluxbox-keys");
	  }
	  //Compositing manager
	  setupCompositor();
  } else {
	if(!LUtils::isValidBinary(WM)){
	  exit(1);
	}
	startProcess("wm", WM);
  }
  //Desktop Next
  LSingleApplication::removeLocks("lumina-desktop");
  startProcess("runtime","lumina-desktop");
  //ScreenSaver
  if(LUtils::isValidBinary("xscreensaver")){ startProcess("screensaver","xscreensaver -no-splash"); }
 }else{
  //unified process
  setupCompositor(true); //required for Lumina 2
  LSingleApplication::removeLocks("lumina-desktop-unified");
  startProcess("runtime","lumina-desktop-unified");
 }
}

void LSession::checkFiles(){
//internal version conversion examples:
  //  [1.0.0 -> 1000000], [1.2.3 -> 1002003], [0.6.1 -> 6001]
  qDebug() << "[Lumina] Checking User Files";
  QSettings sset("lumina-desktop", "sessionsettings");
  QString OVS = sset.value("DesktopVersion","0").toString(); //Old Version String
  qDebug() << " - Old Version:" << OVS;
  qDebug() << " - Current Version:" << LDesktopUtils::LuminaDesktopVersion();
  bool changed = LDesktopUtils::checkUserFiles(OVS, LDesktopUtils::LuminaDesktopVersion());
  qDebug() << " - Made Changes:" << changed;
  if(changed){
    //Save the current version of the session to the settings file (for next time)
    sset.setValue("DesktopVersion", LDesktopUtils::LuminaDesktopVersion());
  }
  qDebug() << "Finished with user files check";
}
<|endoftext|>


<commit_before>
#include <stdlib.h>

extern "C"
{

typedef unsigned int uint32_t;

void prvGetRegistersFromStack( uint32_t *pulFaultStackAddress )
{
/* These are volatile to try and prevent the compiler/linker optimising them
away as the variables never actually get used.  If the debugger won't show the
values of the variables, make them global my moving their declaration outside
of this function. */
volatile uint32_t r0;
volatile uint32_t r1;
volatile uint32_t r2;
volatile uint32_t r3;
volatile uint32_t r12;
volatile uint32_t lr; /* Link register. */
volatile uint32_t pc; /* Program counter. */
volatile uint32_t psr;/* Program status register. */

    r0 = pulFaultStackAddress[ 0 ];
    r1 = pulFaultStackAddress[ 1 ];
    r2 = pulFaultStackAddress[ 2 ];
    r3 = pulFaultStackAddress[ 3 ];

    r12 = pulFaultStackAddress[ 4 ];
    lr = pulFaultStackAddress[ 5 ];
    pc = pulFaultStackAddress[ 6 ];
    psr = pulFaultStackAddress[ 7 ];

    /* When the following line is hit, the variables contain the register values. */
    for( ;; );
}

/* The prototype shows it is a naked function - in effect this is just an
assembly function. */
void HardFault_Handler( void ) __attribute__( ( naked ) );

/* The fault handler implementation calls a function called
prvGetRegistersFromStack(). */
void HardFault_Handler(void)
{
    __asm volatile
    (
        " tst lr, #4                                                \n"
        " ite eq                                                    \n"
        " mrseq r0, msp                                             \n"
        " mrsne r0, psp                                             \n"
        " ldr r1, [r0, #24]                                         \n"
        " ldr r2, handler2_address_const                            \n"
        " bx r2                                                     \n"
        " handler2_address_const: .word prvGetRegistersFromStack    \n"
    );
}

}

int main(void)
{
	unsigned int* heap_size = 0;
	int ctr = 0;
	void* tab_mem[3];
	//unsigned int  wait = 1;

	//while (wait);

	while ((tab_mem[ctr] = malloc(1024)) != 0)
	{
		ctr++;
		heap_size += 1024;
	}

	while (1);

	return 1;
}
<commit_msg>fix bug in heap_size calculation<commit_after>
#include <stdlib.h>

extern "C"
{

typedef unsigned int uint32_t;

void prvGetRegistersFromStack( uint32_t *pulFaultStackAddress )
{
/* These are volatile to try and prevent the compiler/linker optimising them
away as the variables never actually get used.  If the debugger won't show the
values of the variables, make them global my moving their declaration outside
of this function. */
volatile uint32_t r0;
volatile uint32_t r1;
volatile uint32_t r2;
volatile uint32_t r3;
volatile uint32_t r12;
volatile uint32_t lr; /* Link register. */
volatile uint32_t pc; /* Program counter. */
volatile uint32_t psr;/* Program status register. */

    r0 = pulFaultStackAddress[ 0 ];
    r1 = pulFaultStackAddress[ 1 ];
    r2 = pulFaultStackAddress[ 2 ];
    r3 = pulFaultStackAddress[ 3 ];

    r12 = pulFaultStackAddress[ 4 ];
    lr = pulFaultStackAddress[ 5 ];
    pc = pulFaultStackAddress[ 6 ];
    psr = pulFaultStackAddress[ 7 ];

    /* When the following line is hit, the variables contain the register values. */
    for( ;; );
}

/* The prototype shows it is a naked function - in effect this is just an
assembly function. */
void HardFault_Handler( void ) __attribute__( ( naked ) );

/* The fault handler implementation calls a function called
prvGetRegistersFromStack(). */
void HardFault_Handler(void)
{
    __asm volatile
    (
        " tst lr, #4                                                \n"
        " ite eq                                                    \n"
        " mrseq r0, msp                                             \n"
        " mrsne r0, psp                                             \n"
        " ldr r1, [r0, #24]                                         \n"
        " ldr r2, handler2_address_const                            \n"
        " bx r2                                                     \n"
        " handler2_address_const: .word prvGetRegistersFromStack    \n"
    );
}

}

int main(void)
{
	unsigned char* heap_size = 0;
	int ctr = 0;

	while (malloc(1024) != 0)
	{
		ctr++;
		heap_size += 1024;
	}

	while (1);

	return 1;
}
<|endoftext|>