Example #1
0
 /**
  * Checks in the message.  If the message was checked out for
  * writing, the buffer will be committed and returned to the
  * object_allocator if allow_simultaneous_rw is not set, the
  * buffer will be committing regardless of whether there is an
  * existing reader.  If it is set, the thread will wait until
  * there are no readers before committing the buffer.  Returns the
  * norm of the change of value. (using the norm() function) if its
  * a write checkin. Returns 0 otherwise.
  *
  * \warning writes may block for extended periods if there are
  * readers
  */
 double checkin(object_allocator_tls<F> &pool, 
                const F *msg, const factor_norm<F>& norm, 
                const bool allow_simultaneous_rw) {
   double residual = -1;
   lock.lock();
   // if it matches message address, this was a read request
   if (msg == &message) {
     assert(readercount > 0);
     readercount--;
   }
   //this was a write request
   else if (msg == writebuffer) {
     //Optional: Wait for readers to complete
     if (!allow_simultaneous_rw) {
       while(readercount > 0) {
         lock.unlock();
         sched_yield();
         lock.lock();
       }
     }
     // compute the delta
     residual = norm(message , *(writebuffer));
     message = *(writebuffer);
     pool.checkin(writebuffer);
     writebuffer = NULL;
     lastresidual = residual;
   }
   else {
     //Erroneous message!
     assert(0);
   }
   lock.unlock();
   return residual;
 }
Example #2
0
// k_heap_compress - Merge free blocks
// This function "compresses" the linked list, consolidating as many adjacent free blocks as possible, to reduce fragmentation.
int k_heap_compress() {
    k_heap_blk* blk = heap.start;
    k_heap_blk* next = NULL;
    int blks_deleted = 0;
    
    __dynmem_lock.lock_cli();
    while((blk != NULL) && (blk->next != NULL)) { // Don't compress the first or last block in the heap.
        next = blk->next;
        if(blk->prev != NULL) {
            if(!blk->used && !blk->prev->used) { // If both the current block and the one before it are free...
                // ...then _delete_ this block. 
                k_heap_delete(blk);
                blks_deleted++;
            }
        }
        blk = next;
    }
    
    if((heap.end->prev != NULL) && (!heap.end->prev->used)) {
        k_heap_delete(heap.end);
        blks_deleted++;
    }
    __dynmem_lock.unlock_cli();
    return blks_deleted;
}
Example #3
0
// kfree - free memory block
// This function frees a block of memory given by kmalloc(), allowing other kernel tasks to use it.
void kfree(char* ptr) {
    // given a pointer to a block of memory:
    // find the header for that block of memory
    // set the free bit
    // compress the list
    k_heap_blk *header_ptr = (k_heap_blk*)((size_t)(ptr-sizeof(k_heap_blk)-1));
    __dynmem_lock.lock();
#ifdef DYNMEM_CHECK_FREE_CALLS
    if(header_ptr->magic == HEAP_MAGIC_NUMBER) {
#endif
        header_ptr->used = false;
        if(header_ptr->prev != NULL) {
            if( !(header_ptr->prev->used) ) {
                // Just delete this block.
                k_heap_delete(header_ptr);
            } 
        }
        if(header_ptr->next != NULL) {
            if( !(header_ptr->next->used) ) {
                // Delete header_ptr->next.
                k_heap_blk *next = header_ptr->next;
                k_heap_delete(next);
            }
        }
        
        //k_heap_compress();
#ifdef DYNMEM_CHECK_FREE_CALLS
    } else {
        // We're freeing an invalid pointer.
        panic("dynmem: bad free() call -- could not find magic number\ndynmem: Pointer points to: 0x%x.\n", (unsigned long long int)((size_t)ptr) );
    }
#endif
    __dynmem_lock.unlock();
}
Example #4
0
char* kmalloc(size_t size) {
    // iterate over every block in the heap list except for the last one
    // and look for a block where the space between the block and the next in the list is at least size bytes...
    // if we can't find one, extend the heap.
    int n_blks = (size / HEAP_BLK_SIZE)+1;
    char* ptr = NULL;
    k_heap_blk* blk = heap.start;
    __dynmem_lock.lock();
    while(blk->next != NULL) {
        if(!blk->used) {
            int blk_sz = ((size_t)blk->next - (size_t)blk);
            if( blk_sz-sizeof(k_heap_blk) >= size ) {
                blk->used = true;
                char* ptr = NULL;
                if( (blk_sz / HEAP_BLK_SIZE) > n_blks ) {
                    k_heap_add_at_offset(blk, n_blks);
                    blk->next->used = false;
                    ptr = (char*)((size_t)blk+sizeof(k_heap_blk)+1);
                } else {
                    ptr = (char*)((size_t)blk+sizeof(k_heap_blk)+1);
                }
                break;
            }
        }
        blk = blk->next;
    }
    if(ptr == NULL) { // if we still haven't allocated memory, then make a new block.
        k_heap_add_at_offset(heap.end, n_blks);
        heap.end->prev->used = true;
        ptr = (char*)((size_t)(heap.end->prev)+sizeof(k_heap_blk)+1);
    }
    __dynmem_lock.unlock();
    return ptr;
}
Example #5
0
// terminal_writestring - print a string to screen
// this function prints a line of text to screen, wrapping and scrolling if necessary.
void terminal_writestring(char* data)
{
    __vga_write_lock.lock();
	size_t datalen = strlen(data);
	for ( size_t i = 0; i < datalen; i++ ) {
		terminal_putchar(data[i]);
    }
    __vga_write_lock.unlock();
}
Example #6
0
        virtual void invoke()
        {
#ifdef DEBUG
            s_locker.lock();
            s_fibers.remove(&m_fb->m_link);
            s_locker.unlock();
#endif

            m_fb->m_joins.set();
            m_fb->Unref();
        }
Example #7
0
void terminal_backspace() {
    __vga_write_lock.lock();
    if(--terminal_column > VGA_WIDTH) {
        if(--terminal_row > VGA_HEIGHT) {
            terminal_scroll(-1);
            terminal_row = 0;
        }
    }
    terminal_putentryat(' ', terminal_color, terminal_column, terminal_row);
    __vga_write_lock.unlock();
}
 bool find(data item) {
     size_t bucket = hashfn(item) % buckets.size();
     lock.lock();
     for (auto it = buckets[bucket].begin(); it != buckets[bucket].end(); it++) {
         if (*it == item) {
             lock.unlock();
             return true;
         }
     }
     lock.unlock();
     return false;
 }
Example #9
0
void Service::Create(fiber_func func, void *data, int32_t stacksize, const char* name, Fiber** retVal)
{
    Fiber *fb;
    void **stack;

    stacksize = (stacksize + FB_STK_ALIGN - 1) & ~(FB_STK_ALIGN - 1);
#ifdef WIN32
    fb = (Fiber *) VirtualAlloc(NULL, stacksize, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE);
#else
    fb = (Fiber *) malloc(stacksize);
#endif
    if (fb == NULL)
        return;

    stack = (void **) fb + stacksize / sizeof(void *) - 5;

    new(fb) Fiber(s_service, data);

    fb->m_cntxt.ip = (intptr_t) fiber_proc;
    fb->m_cntxt.sp = (intptr_t) stack;

#if defined(x64)
#ifdef _WIN32
    fb->m_cntxt.Rcx = (intptr_t) func;
    fb->m_cntxt.Rdx = (intptr_t) fb;
#else
    fb->m_cntxt.Rdi = (intptr_t) func;
    fb->m_cntxt.Rsi = (intptr_t) fb;
#endif
#elif defined(I386)
    stack[1] = (void *)func;
    stack[2] = fb;
#elif defined(arm)
    fb->m_cntxt.r0 = (intptr_t) func;
    fb->m_cntxt.r1 = (intptr_t) fb;
#endif

#ifdef DEBUG
    s_locker.lock();
    s_fibers.putTail(&fb->m_link);
    s_locker.unlock();
#endif

    if (retVal)
    {
        *retVal = fb;
        fb->Ref();
    }

    fb->Ref();
    fb->resume();
}
Example #10
0
// k_heap_add_at_offset - Add a new heap block
// This function places a new heap block in memory, linked to an "origin" block.
void k_heap_add_at_offset(k_heap_blk* origin_blk, int block_offset) {
    __dynmem_lock.lock_cli();
    k_heap_blk* blk = (k_heap_blk*)((size_t)origin_blk+(block_offset*HEAP_BLK_SIZE));
    blk->prev = origin_blk;
    blk->next = origin_blk->next;
    blk->magic = HEAP_MAGIC_NUMBER;
    
    blk->prev->next = blk;
    if(blk->next != NULL)
        blk->next->prev = blk;
    else
        heap.end = blk;
    __dynmem_lock.unlock_cli();
}
Example #11
0
void Service::forEach(void (*func)(Fiber*))
{
    s_locker.lock();

    linkitem* p = s_fibers.head();

    while (p)
    {
        Fiber* zfb = 0;
        func((Fiber*)((intptr_t)p - (intptr_t)(&zfb->m_link)));

        p = s_fibers.next(p);
    }

    s_locker.unlock();
}
Example #12
0
 /**
  * Checks the message.  If its a write request, a buffer will be
  * taken from the object_allocator.  If the object is currently
  * allocated for writing then this function will return NULL
  */
 F *trycheckout(object_allocator_tls<F> &pool, 
             const ReadWrite rw) {
   if (rw == Reading) {
     return checkout(pool,rw);
   }
   else {
     lock.lock();
     if (writebuffer != NULL) {
       lock.unlock();
       return NULL;
     }
     writebuffer = pool.checkout();
     lock.unlock();
     (*writebuffer) = message;
     return writebuffer;
   }
 }
Example #13
0
// terminal_scroll - scroll the console
// Positive values scroll down (adding new lines to the bottom); negative values do the inverse.
void terminal_scroll(int num_rows)
{
    __vga_write_lock.lock();
    if(num_rows > 0) { // scroll down
        for(size_t y=0;y<VGA_HEIGHT-1;y++)
            for(size_t x=0;x<VGA_WIDTH;x++)
                terminal_buffer[y*VGA_WIDTH+x] = terminal_buffer[(y+1)*VGA_WIDTH+x];
        for(size_t x=0;x<VGA_WIDTH;x++)
            terminal_buffer[(VGA_HEIGHT-1)*VGA_WIDTH+x] = make_vgaentry(' ', make_color(COLOR_LIGHT_GREY, COLOR_BLACK));
    } else if(num_rows < 0) { // scroll up
        for(size_t y=VGA_HEIGHT-1;y>0;y--)
            for(size_t x=0;x<VGA_WIDTH;x++)
                terminal_buffer[y*VGA_WIDTH+x] = terminal_buffer[(y-1)*VGA_WIDTH+x];
        for(size_t x=0;x<VGA_WIDTH;x++)
            terminal_buffer[x] = make_vgaentry(' ', make_color(COLOR_LIGHT_GREY, COLOR_BLACK));
    }
    __vga_write_lock.unlock();
}
    void notify_all() const
    {
        spinlock_.lock();

        broadcasting_ = waiters_ > 0;

        if ( broadcasting_ )
        {
            ZI_VERIFY( win32::ReleaseSemaphore( semaphore_, waiters_, 0 ) );
            spinlock_.unlock();
            ZI_VERIFY_0( win32::WaitForSingleObject( last_event_, win32::forever ) );
            broadcasting_ = 0;
        }
        else
        {
            spinlock_.unlock();
        }
    }
Example #15
0
    /**
     * Checks the message.  If its a write request, a buffer will be
     * taken from the object_allocator
     */
    F *checkout(object_allocator_tls<F> &pool, 
                const ReadWrite rw) {
      if (rw == Reading) {
        lock.lock();
        readercount++;
        lock.unlock();
        return &message;
      }
      else {
        lock.lock();
        // we only support 1 writer. 
        assert(writebuffer == NULL);
        writebuffer = pool.checkout();
        lock.unlock();
        (*writebuffer) = message;

        return writebuffer;
      }
    }
Example #16
0
// k_heap_delete - Unlink a block
// This function removes a block from the linked list, effectively "deleting" it.
void k_heap_delete(k_heap_blk* blk) {
    __dynmem_lock.lock_cli();
    if(blk == NULL) {
        panic("dynmem: Attempted to delete NULL block!");
    }
    if(blk->prev != NULL) {
        blk->prev->next = blk->next;
    } else {
        return; // can't delete the first block
    }
    if(blk->next != NULL) {
        blk->next->prev = blk->prev;
    } else {
        heap.end = blk->prev;
    }
    blk->next = NULL;
    blk->prev = NULL;
    blk->magic = 0;
    blk->used = false;
    __dynmem_lock.unlock_cli();
}
Example #17
0
// terminal_putchar - write a single character to screen
// This function prints a character to screen in a manner similar to "terminal_writestring" (see below).
// '\n' characters are automatically used to scroll and start new lines.
void terminal_putchar(char c)
{
    __vga_write_lock.lock();
    if(c=='\n') {
        terminal_column = 0;
        if ( ++terminal_row == VGA_HEIGHT ) {
            terminal_scroll(1);
            terminal_row = VGA_HEIGHT-1;
        }
        __vga_write_lock.unlock();
        return;
    }
	terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
	if ( ++terminal_column == VGA_WIDTH )
	{
		terminal_column = 0;
		if ( ++terminal_row == VGA_HEIGHT )
		{
			terminal_scroll(1);
            terminal_row = VGA_HEIGHT-1;
		}
	}
    __vga_write_lock.unlock();
}
Example #18
0
 explicit scoped_lock( spinlock & sp ): sp_( sp )
 {
     sp.lock();
 }
Example #19
0
void OSThread::suspend(spinlock& lock)
{
    lock.unlock();
    suspend();
}
Example #20
0
/**
 * Body of the main profiler thread
 */
void profiler::profiler_thread(spinlock& l) {
  // Open the output file
  ofstream output;
  output.open(_output_filename, ios_base::app);
  output.rdbuf()->pubsetbuf(0, 0);
  output.setf(ios::fixed, ios::floatfield);
  output.precision(2);

  // Initialize the delay size RNG
  default_random_engine generator(get_time());
  uniform_int_distribution<size_t> delay_dist(0, ZeroSpeedupWeight + SpeedupDivisions);

  // Initialize the experiment duration
  size_t experiment_length = ExperimentMinTime;

  // Get the starting time for the profiler
  size_t start_time = get_time();

  // Log the start of this execution
  output << "startup\t"
         << "time=" << start_time << "\n";

  // Unblock the main thread
  l.unlock();

  // Wait until there is at least one progress point
  _throughput_points_lock.lock();
  _latency_points_lock.lock();
  while(_throughput_points.size() == 0 && _latency_points.size() == 0 && _running) {
    _throughput_points_lock.unlock();
    _latency_points_lock.unlock();
    wait(ExperimentCoolOffTime);
    _throughput_points_lock.lock();
    _latency_points_lock.lock();
  }
  _throughput_points_lock.unlock();
  _latency_points_lock.unlock();

  // Log sample counts after this many experiments (doubles each time)
  size_t sample_log_interval = 32;
  size_t sample_log_countdown = sample_log_interval;

  // Main experiment loop
  while(_running) {
    // Select a line
    line* selected;
    if(_fixed_line) {   // If this run has a fixed line, use it
      selected = _fixed_line;
    } else {            // Otherwise, wait for the next line to be selected
      selected = _next_line.load();
      while(_running && selected == nullptr) {
        wait(SamplePeriod * SampleBatchSize);
        selected = _next_line.load();
      }

      // If we're no longer running, exit the experiment loop
      if(!_running) break;

      _selected_line.store(selected);
    }

    // Choose a delay size
    size_t delay_size;
    if(_fixed_delay_size >= 0) {
      delay_size = _fixed_delay_size;
    } else {
      size_t r = delay_dist(generator);
      if(r <= ZeroSpeedupWeight) {
        delay_size = 0;
      } else {
        delay_size = (r - ZeroSpeedupWeight) * SamplePeriod / SpeedupDivisions;
      }
    }

    _delay_size.store(delay_size);

    // Save the starting time and sample count
    size_t start_time = get_time();
    size_t starting_samples = selected->get_samples();
    size_t starting_delay_time = _global_delay.load();
    
    // Was arrival speedup enabled?
    int arrival_speedup_percent;
    // Yes. Choose a random arrival speedup size using the same procedure as for line speedup size
    if(_enable_arrival_speedup) {
      size_t r = delay_dist(generator);
      if(r <= ZeroSpeedupWeight) {
        arrival_speedup_percent = 0;
      } else {
        arrival_speedup_percent = (r - ZeroSpeedupWeight) * 100 / SpeedupDivisions;
      }
    }

    // Save throughput point values at the start of the experiment
    vector<unique_ptr<throughput_point::saved>> saved_throughput_points;
    _throughput_points_lock.lock();
    for(pair<const std::string, throughput_point*>& p : _throughput_points) {
      saved_throughput_points.emplace_back(p.second->save());
    }
    _throughput_points_lock.unlock();
    
    // Save latency point values at the start of the experiment
    vector<unique_ptr<latency_point::saved>> saved_latency_points;
    _latency_points_lock.lock();
    for(pair<const std::string, latency_point*>& p : _latency_points) {
      saved_latency_points.emplace_back(p.second->save());
    }
    _latency_points_lock.unlock();

    // Tell threads to start the experiment
    _experiment_active.store(true);

    // If arrival speedup is enabled, profiler thread samples the arrival point
    // Otherwise, just wait until experiment ends
    if(_enable_arrival_speedup) {
      size_t elapsed_time = 0;
      while(elapsed_time < experiment_length) {
        // Wait for a sampling period
        size_t period = wait(SamplePeriod);
        // Compute the amount of delay to add to all running threads
        size_t delay_size = (period * arrival_speedup_percent) / 100;
        // Add the delay
        _global_delay += delay_size;
        // Add this period to elapsed time
        elapsed_time += period;
      }
    } else {
      // Wait for the experiment duration to elapse
      wait(experiment_length);
    }

    // Compute experiment parameters
    float speedup = (float)delay_size / (float)SamplePeriod;
    size_t experiment_delay = _global_delay.load() - starting_delay_time;
    size_t duration = get_time() - start_time - experiment_delay;
    size_t selected_samples = selected->get_samples() - starting_samples;

    // Log the experiment parameters
    output << "experiment\t"
           << "selected=" << selected << "\t"
           << "speedup=" << speedup << "\t"
           << "duration=" << duration << "\t"
           << "selected-samples=" << selected_samples << "\n";

    // Keep a running count of the minimum delta over all progress points
    size_t min_delta = std::numeric_limits<size_t>::max();
    
    // Log throughput point measurements and update the minimum delta
    for(const auto& s : saved_throughput_points) {
      size_t delta = s->get_delta();
      if(delta < min_delta) min_delta = delta;
      s->log(output);
    }
    
    // Log latency point measurements and update the minimum delta
    for(const auto& s : saved_latency_points) {
      size_t begin_delta = s->get_begin_delta();
      size_t end_delta = s->get_end_delta();
      if(begin_delta < min_delta) min_delta = begin_delta;
      if(end_delta < min_delta) min_delta = end_delta;
      s->log(output);
    }

    // Lengthen the experiment if the min_delta is too small
    if(min_delta < ExperimentTargetDelta) {
      experiment_length *= 2;
    } else if(min_delta > ExperimentTargetDelta*2 && experiment_length >= ExperimentMinTime*2) {
      experiment_length /= 2;
    }

    output.flush();

    // Clear the next line, so threads will select one
    _next_line.store(nullptr);

    // End the experiment
    _experiment_active.store(false);

    // Log samples after a while, then double the countdown
    if(--sample_log_countdown == 0) {
      log_samples(output, start_time);
      if(sample_log_interval < 20) {
        sample_log_interval *= 2;
      }
      sample_log_countdown = sample_log_interval;
    }

    // Cool off before starting a new experiment, unless the program is exiting
    if(_running) wait(ExperimentCoolOffTime);
  }

  // Log the sample counts on exit
  log_samples(output, start_time);

  output.flush();
  output.close();
}
 void insert(data item) {
     size_t bucket = hashfn(item) % buckets.size();
     lock.lock();
     buckets[bucket].push_back(item);
     lock.unlock();
 }
Example #22
0
namespace exlib
{

#define FB_STK_ALIGN 256

void init_timer();

static bool s_service_inited;
static Service* s_service = NULL;

void Service::init(int32_t workers)
{
    if (!s_service)
    {
        static Service _srv(workers);
        s_service = &_srv;
        s_service->m_main.saveStackGuard();
        s_service->bindCurrent();
    }
}

Thread_base* Thread_base::current()
{
    if (!s_service_inited)
        return 0;

    OSThread* thread_ = OSThread::current();

    if (thread_ == 0)
        return 0;

    if (thread_->is(Service::type))
        return ((Service*)thread_)->running();
    return thread_;
}

Service *Service::current()
{
    OSThread* thread_ = OSThread::current();

    assert(s_service_inited);
    assert(thread_ != 0);
    assert(thread_->is(Service::type));

    return (Service*)thread_;
}

#ifdef DEBUG

static LockedList<linkitem> s_fibers;
static spinlock s_locker;

void Service::forEach(void (*func)(Fiber*))
{
    s_locker.lock();

    linkitem* p = s_fibers.head();

    while (p)
    {
        Fiber* zfb = 0;
        func((Fiber*)((intptr_t)p - (intptr_t)(&zfb->m_link)));

        p = s_fibers.next(p);
    }

    s_locker.unlock();
}

#endif

Service::Service() :
    m_master(s_service), m_main(this, NULL), m_running(&m_main), m_cb(NULL)
{
    m_main.set_name("main");
    m_main.Ref();
}

Service::Service(int32_t workers) :
    m_master(NULL), m_main(this, NULL), m_running(&m_main), m_cb(NULL), m_workers(workers - 1)
{
    m_main.set_name("main");
    m_main.Ref();

    if (!s_service_inited)
    {
        s_service_inited = true;
        init_timer();
    }
}

void Service::fiber_proc(void *(*func)(void *), Fiber *fb)
{
    class cb : public Service::switchConextCallback
    {
    public:
        cb(Fiber* fb) : m_fb(fb)
        {}

    public:
        virtual void invoke()
        {
#ifdef DEBUG
            s_locker.lock();
            s_fibers.remove(&m_fb->m_link);
            s_locker.unlock();
#endif

            m_fb->m_joins.set();
            m_fb->Unref();
        }

    private:
        Fiber* m_fb;
    } _cb(fb);

    fb->saveStackGuard();
    func(fb->m_data);

    Service* now = fb->m_pService;
    now->switchConext(&_cb);
}

void Service::Create(fiber_func func, void *data, int32_t stacksize, const char* name, Fiber** retVal)
{
    Fiber *fb;
    void **stack;

    stacksize = (stacksize + FB_STK_ALIGN - 1) & ~(FB_STK_ALIGN - 1);
#ifdef WIN32
    fb = (Fiber *) VirtualAlloc(NULL, stacksize, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE);
#else
    fb = (Fiber *) malloc(stacksize);
#endif
    if (fb == NULL)
        return;

    stack = (void **) fb + stacksize / sizeof(void *) - 5;

    new(fb) Fiber(s_service, data);

    fb->m_cntxt.ip = (intptr_t) fiber_proc;
    fb->m_cntxt.sp = (intptr_t) stack;

#if defined(x64)
#ifdef _WIN32
    fb->m_cntxt.Rcx = (intptr_t) func;
    fb->m_cntxt.Rdx = (intptr_t) fb;
#else
    fb->m_cntxt.Rdi = (intptr_t) func;
    fb->m_cntxt.Rsi = (intptr_t) fb;
#endif
#elif defined(I386)
    stack[1] = (void *)func;
    stack[2] = fb;
#elif defined(arm)
    fb->m_cntxt.r0 = (intptr_t) func;
    fb->m_cntxt.r1 = (intptr_t) fb;
#endif

#ifdef DEBUG
    s_locker.lock();
    s_fibers.putTail(&fb->m_link);
    s_locker.unlock();
#endif

    if (retVal)
    {
        *retVal = fb;
        fb->Ref();
    }

    fb->Ref();
    fb->resume();
}

void Service::dispatch()
{
    assert(s_service != 0);
    s_service->dispatch_loop();
}

void Service::dispatch_loop()
{
    while (true)
    {
        m_running = &m_main;

        if (m_cb)
        {
            m_cb->invoke();
            m_cb = NULL;
        }

        Fiber *fb = next();
        assert(fb != 0);

        m_running = fb;
        fb->m_pService = this;
        m_main.m_cntxt.switchto(&fb->m_cntxt);
    }
}

}