ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
(Generate patch)

Comparing deliantra/server/lib/cf.pm (file contents):
Revision 1.568 by root, Tue May 3 17:12:14 2011 UTC vs.
Revision 1.571 by root, Wed May 4 19:04:45 2011 UTC

131our @EXTRA_MODULES = qw(pod match mapscript incloader); 131our @EXTRA_MODULES = qw(pod match mapscript incloader);
132 132
133our %CFG; 133our %CFG;
134 134
135our $UPTIME; $UPTIME ||= time; 135our $UPTIME; $UPTIME ||= time;
136our $RUNTIME; 136our $RUNTIME = 0;
137our $SERVER_TICK = 0;
137our $NOW; 138our $NOW;
138 139
139our (%PLAYER, %PLAYER_LOADING); # all users 140our (%PLAYER, %PLAYER_LOADING); # all users
140our (%MAP, %MAP_LOADING ); # all maps 141our (%MAP, %MAP_LOADING ); # all maps
141our $LINK_MAP; # the special {link} map, which is always available 142our $LINK_MAP; # the special {link} map, which is always available
150 151
151our @POST_INIT; 152our @POST_INIT;
152 153
153our $REATTACH_ON_RELOAD; # set to true to force object reattach on reload (slow) 154our $REATTACH_ON_RELOAD; # set to true to force object reattach on reload (slow)
154our $REALLY_UNLOOP; # never set to true, please :) 155our $REALLY_UNLOOP; # never set to true, please :)
156
157our $WAIT_FOR_TICK = new Coro::Signal;
158our @WAIT_FOR_TICK_BEGIN;
155 159
156binmode STDOUT; 160binmode STDOUT;
157binmode STDERR; 161binmode STDERR;
158 162
159# read virtual server time, if available 163# read virtual server time, if available
193 197
194=over 4 198=over 4
195 199
196=item $cf::UPTIME 200=item $cf::UPTIME
197 201
198The timestamp of the server start (so not actually an uptime). 202The timestamp of the server start (so not actually an "uptime").
203
204=item $cf::SERVER_TICK
205
206An unsigned integer that starts at zero when the server is started and is
207incremented on every tick.
208
209=item $cf::NOW
210
211The (real) time of the last (current) server tick - updated before and
212after tick processing, so this is useful only as a rough "what time is it
213now" estimate.
214
215=item $cf::TICK
216
217The interval between each server tick, in seconds.
199 218
200=item $cf::RUNTIME 219=item $cf::RUNTIME
201 220
202The time this server has run, starts at 0 and is increased by $cf::TICK on 221The time this server has run, starts at 0 and is increased by $cf::TICK on
203every server tick. 222every server tick.
209Various directories - "/etc", read-only install directory, perl-library 228Various directories - "/etc", read-only install directory, perl-library
210directory, pod-directory, read-only maps directory, "/var", "/var/tmp", 229directory, pod-directory, read-only maps directory, "/var", "/var/tmp",
211unique-items directory, player file directory, random maps directory and 230unique-items directory, player file directory, random maps directory and
212database environment. 231database environment.
213 232
214=item $cf::NOW
215
216The time of the last (current) server tick.
217
218=item $cf::TICK
219
220The interval between server ticks, in seconds.
221
222=item $cf::LOADAVG 233=item $cf::LOADAVG
223 234
224The current CPU load on the server (alpha-smoothed), as a value between 0 235The current CPU load on the server (alpha-smoothed), as a value between 0
225(none) and 1 (overloaded), indicating how much time is spent on processing 236(none) and 1 (overloaded), indicating how much time is spent on processing
226objects per tick. Healthy values are < 0.5. 237objects per tick. Healthy values are < 0.5.
237=item cf::wait_for_tick, cf::wait_for_tick_begin 248=item cf::wait_for_tick, cf::wait_for_tick_begin
238 249
239These are functions that inhibit the current coroutine one tick. cf::wait_for_tick_begin only 250These are functions that inhibit the current coroutine one tick. cf::wait_for_tick_begin only
240returns directly I<after> the tick processing (and consequently, can only wake one thread 251returns directly I<after> the tick processing (and consequently, can only wake one thread
241per tick), while cf::wait_for_tick wakes up all waiters after tick processing. 252per tick), while cf::wait_for_tick wakes up all waiters after tick processing.
253
254Note that cf::Wait_for_tick will immediately return when the server is not
255ticking, making it suitable for small pauses in threads that need to run
256when the server is paused. If that is not applicable (i.e. you I<really>
257want to wait, use C<$cf::WAIT_FOR_TICK>).
258
259=item $cf::WAIT_FOR_TICK
260
261Note that C<cf::wait_for_tick> is probably the correct thing to use. This
262variable contains a L<Coro::Signal> that is broadcats after every server
263tick. Calling C<< ->wait >> on it will suspend the caller until after the
264next server tick.
242 265
243=cut 266=cut
244 267
245sub wait_for_tick(); 268sub wait_for_tick();
246sub wait_for_tick_begin(); 269sub wait_for_tick_begin();
545 } 568 }
546 } 569 }
547 570
548 if (@SLOT_QUEUE) { 571 if (@SLOT_QUEUE) {
549 # we do not use wait_for_tick() as it returns immediately when tick is inactive 572 # we do not use wait_for_tick() as it returns immediately when tick is inactive
550 push @cf::WAIT_FOR_TICK, $signal; 573 $WAIT_FOR_TICK->wait;
551 $signal->wait;
552 } else { 574 } else {
553 $busy = 0; 575 $busy = 0;
554 Coro::schedule; 576 Coro::schedule;
555 } 577 }
556 } 578 }
2171 2193
2172 { 2194 {
2173 my $guard = cf::lock_acquire "map_data:$path"; 2195 my $guard = cf::lock_acquire "map_data:$path";
2174 2196
2175 return unless $self->valid; 2197 return unless $self->valid;
2176 return unless $self->in_memory == cf::MAP_SWAPPED; 2198 return unless $self->state == cf::MAP_SWAPPED;
2177
2178 $self->in_memory (cf::MAP_LOADING);
2179 2199
2180 $self->alloc; 2200 $self->alloc;
2181 2201
2182 $self->pre_load; 2202 $self->pre_load;
2183 cf::cede_to_tick; 2203 cf::cede_to_tick;
2206 } else { 2226 } else {
2207 $self->post_load_original 2227 $self->post_load_original
2208 if delete $self->{load_original}; 2228 if delete $self->{load_original};
2209 } 2229 }
2210 2230
2231 $self->state (cf::MAP_INACTIVE);
2232
2211 cf::cede_to_tick; 2233 cf::cede_to_tick;
2212 # now do the right thing for maps 2234 # now do the right thing for maps
2213 $self->link_multipart_objects; 2235 $self->link_multipart_objects;
2214 $self->difficulty ($self->estimate_difficulty) 2236 $self->difficulty ($self->estimate_difficulty)
2215 unless $self->difficulty; 2237 unless $self->difficulty;
2217 2239
2218 unless ($self->{deny_activate}) { 2240 unless ($self->{deny_activate}) {
2219 $self->decay_objects; 2241 $self->decay_objects;
2220 $self->fix_auto_apply; 2242 $self->fix_auto_apply;
2221 $self->update_buttons; 2243 $self->update_buttons;
2244 $self->post_load_physics;
2222 cf::cede_to_tick; 2245 cf::cede_to_tick;
2223 #$self->activate; # no longer activate maps automatically 2246 #$self->activate; # no longer activate maps automatically
2224 } 2247 }
2225 2248
2226 $self->{last_save} = $cf::RUNTIME; 2249 $self->{last_save} = $cf::RUNTIME;
2227 $self->last_access ($cf::RUNTIME); 2250 $self->last_access ($cf::RUNTIME);
2228
2229 $self->in_memory (cf::MAP_ACTIVE);
2230 } 2251 }
2231 2252
2232 $self->post_load; 2253 $self->post_load;
2233 2254
2234 1 2255 1
2277} 2298}
2278 2299
2279sub find_sync { 2300sub find_sync {
2280 my ($path, $origin) = @_; 2301 my ($path, $origin) = @_;
2281 2302
2303 # it's a bug to call this from the main context
2282 return cf::LOG cf::llevError | cf::logBacktrace, "do_find_sync" 2304 return cf::LOG cf::llevError | cf::logBacktrace, "do_find_sync"
2283 if $Coro::current == $Coro::main; 2305 if $Coro::current == $Coro::main;
2284 2306
2285 find $path, $origin 2307 find $path, $origin
2286} 2308}
2287 2309
2288sub do_load_sync { 2310sub do_load_sync {
2289 my ($map) = @_; 2311 my ($map) = @_;
2290 2312
2313 # it's a bug to call this from the main context
2291 return cf::LOG cf::llevError | cf::logBacktrace, "do_load_sync" 2314 return cf::LOG cf::llevError | cf::logBacktrace, "do_load_sync"
2292 if $Coro::current == $Coro::main; 2315 if $Coro::current == $Coro::main;
2293 2316
2294 $map->load; 2317 $map->load;
2295} 2318}
2299 2322
2300sub find_async { 2323sub find_async {
2301 my ($path, $origin, $load) = @_; 2324 my ($path, $origin, $load) = @_;
2302 2325
2303 $path = normalise $path, $origin; 2326 $path = normalise $path, $origin;
2304 2327
2305 if (my $map = $cf::MAP{$path}) { 2328 if (my $map = $cf::MAP{$path}) {
2306 return $map if !$load || $map->in_memory == cf::MAP_ACTIVE; 2329 return $map if !$load || $map->linkable;
2307 } 2330 }
2308 2331
2309 $MAP_PREFETCH{$path} |= $load; 2332 $MAP_PREFETCH{$path} |= $load;
2310 2333
2311 $MAP_PREFETCHER ||= cf::async { 2334 $MAP_PREFETCHER ||= cf::async {
2370sub swap_out { 2393sub swap_out {
2371 my ($self) = @_; 2394 my ($self) = @_;
2372 2395
2373 my $lock = cf::lock_acquire "map_data:$self->{path}"; 2396 my $lock = cf::lock_acquire "map_data:$self->{path}";
2374 2397
2375 return if $self->in_memory != cf::MAP_ACTIVE; 2398 return if !$self->linkable;
2376 return if $self->{deny_save}; 2399 return if $self->{deny_save};
2377 return if $self->players; 2400 return if $self->players;
2378 2401
2379 # first deactivate the map and "unlink" it from the core 2402 # first deactivate the map and "unlink" it from the core
2380 $self->deactivate; 2403 $self->deactivate;
2381 $_->clear_links_to ($self) for values %cf::MAP; 2404 $_->clear_links_to ($self) for values %cf::MAP;
2382 $self->in_memory (cf::MAP_SWAPPED); 2405 $self->state (cf::MAP_SWAPPED);
2383 2406
2384 # then atomically save 2407 # then atomically save
2385 $self->_save; 2408 $self->_save;
2386 2409
2387 # then free the map 2410 # then free the map
2413 2436
2414 return if $self->players; 2437 return if $self->players;
2415 2438
2416 cf::trace "resetting map ", $self->path, "\n"; 2439 cf::trace "resetting map ", $self->path, "\n";
2417 2440
2418 $self->in_memory (cf::MAP_SWAPPED); 2441 $self->state (cf::MAP_SWAPPED);
2419 2442
2420 # need to save uniques path 2443 # need to save uniques path
2421 unless ($self->{deny_save}) { 2444 unless ($self->{deny_save}) {
2422 my $uniq = $self->uniq_path; utf8::encode $uniq; 2445 my $uniq = $self->uniq_path; utf8::encode $uniq;
2423 2446
2931 # special map handling 2954 # special map handling
2932 if ($slaying eq "/!") { 2955 if ($slaying eq "/!") {
2933 my $guard = cf::lock_acquire "exit_prepare:$exit"; 2956 my $guard = cf::lock_acquire "exit_prepare:$exit";
2934 2957
2935 prepare_random_map $exit 2958 prepare_random_map $exit
2936 if $slaying eq "/!"; # need to re-check after getting the lock 2959 if $exit->slaying eq "/!"; # need to re-check after getting the lock
2960
2961 $map = $exit->slaying;
2937 2962
2938 } elsif ($slaying eq '!up') { 2963 } elsif ($slaying eq '!up') {
2939 $map = $exit->map->tile_path (cf::TILE_UP); 2964 $map = $exit->map->tile_path (cf::TILE_UP);
2940 $x = $exit->x; 2965 $x = $exit->x;
2941 $y = $exit->y; 2966 $y = $exit->y;
4091 4116
4092############################################################################# 4117#############################################################################
4093 4118
4094my $bug_warning = 0; 4119my $bug_warning = 0;
4095 4120
4096our @WAIT_FOR_TICK;
4097our @WAIT_FOR_TICK_BEGIN;
4098
4099sub wait_for_tick() { 4121sub wait_for_tick() {
4100 return Coro::cede if tick_inhibit || $Coro::current == $Coro::main; 4122 return Coro::AnyEvent::poll if tick_inhibit || $Coro::current == $Coro::main;
4101 4123
4102 my $signal = new Coro::Signal; 4124 $WAIT_FOR_TICK->wait;
4103 push @WAIT_FOR_TICK, $signal;
4104 $signal->wait;
4105} 4125}
4106 4126
4107sub wait_for_tick_begin() { 4127sub wait_for_tick_begin() {
4108 return Coro::cede if tick_inhibit || $Coro::current == $Coro::main; 4128 return Coro::AnyEvent::poll if tick_inhibit || $Coro::current == $Coro::main;
4109 4129
4110 my $signal = new Coro::Signal; 4130 my $signal = new Coro::Signal;
4111 push @WAIT_FOR_TICK_BEGIN, $signal; 4131 push @WAIT_FOR_TICK_BEGIN, $signal;
4112 $signal->wait; 4132 $signal->wait;
4113} 4133}
4117 Carp::cluck "major BUG: server tick called outside of main coro, skipping it" 4137 Carp::cluck "major BUG: server tick called outside of main coro, skipping it"
4118 unless ++$bug_warning > 10; 4138 unless ++$bug_warning > 10;
4119 return; 4139 return;
4120 } 4140 }
4121 4141
4122 cf::server_tick; # one server iteration 4142 cf::one_tick; # one server iteration
4123 4143
4124 #for(1..3e6){} AE::now_update; $NOW=AE::now; # generate load #d# 4144 #for(1..3e6){} AE::now_update; $NOW=AE::now; # generate load #d#
4125 4145
4126 if ($NOW >= $NEXT_RUNTIME_WRITE) { 4146 if ($NOW >= $NEXT_RUNTIME_WRITE) {
4127 $NEXT_RUNTIME_WRITE = List::Util::max $NEXT_RUNTIME_WRITE + 10, $NOW + 5.; 4147 $NEXT_RUNTIME_WRITE = List::Util::max $NEXT_RUNTIME_WRITE + 10, $NOW + 5.;
4133 } 4153 }
4134 4154
4135 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) { 4155 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) {
4136 $sig->send; 4156 $sig->send;
4137 } 4157 }
4138 while (my $sig = shift @WAIT_FOR_TICK) { 4158 $WAIT_FOR_TICK->broadcast;
4139 $sig->send;
4140 }
4141 4159
4142 $LOAD = ($NOW - $TICK_START) / $TICK; 4160 $LOAD = ($NOW - $TICK_START) / $TICK;
4143 $LOADAVG = $LOADAVG * 0.75 + $LOAD * 0.25; 4161 $LOADAVG = $LOADAVG * 0.75 + $LOAD * 0.25;
4144 4162
4145 if (0) { 4163 if (0) {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines