/* * This file is part of Deliantra, the Roguelike Realtime MMORPG. * * Copyright (©) 2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team * * Deliantra is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * The authors can be reached via e-mail to */ #include "global.h" #include "evthread.h" #include "cfperl.h" thread evthread; static ev_loop *loop; #define TICK_CYCLES 4 // the ticker runs TICK_CYCLES times as fast as the main server tick static ev_periodic cede_watcher; // the tick watcher is activated every TICK_CYCLES ev_async tick_watcher; EV_ATOMIC_T coroapi::cede_pending; // it is a bit silly to have to use a mutex, but contention // is basically non-existant, favouring good mutex implementations. static SMUTEX (evthread_mutex); static NV next_tick; NV get_next_tick () { SMUTEX_LOCK (evthread_mutex); NV retval = next_tick; SMUTEX_UNLOCK (evthread_mutex); return retval; } static void cede_cb (EV_P_ ev_periodic *w, int revents) { static int cycle = 0; if (++cycle == TICK_CYCLES) { cycle = 0; SMUTEX_LOCK (evthread_mutex); next_tick = w->at + TICK / TICK_CYCLES * (TICK_CYCLES - 1); SMUTEX_UNLOCK (evthread_mutex); ev_async_send (EV_DEFAULT, &tick_watcher); } coroapi::cede_pending = 1; } static void tick_cb (EV_P_ ev_async *w, int revents) { cfperl_tick (); } static void * evthread_proc (void *arg) { loop = ev_loop_new (0); ev_periodic_init (&cede_watcher, cede_cb, 0, TICK / TICK_CYCLES, 0); ev_periodic_start (loop, &cede_watcher); ev_loop (loop, 0); return 0; } void evthread_start () { I_EV_API ("evthread"); ev_async_init (&tick_watcher, tick_cb); ev_set_priority (&tick_watcher, 1); ev_async_start (EV_DEFAULT, &tick_watcher); evthread.start (evthread_proc); }