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.566 by root, Sun May 1 16:58:16 2011 UTC vs.
Revision 1.572 by root, Sun May 8 11:44:43 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 }
1954 # {... are special paths that are not being touched 1976 # {... are special paths that are not being touched
1955 # ?xxx/... are special absolute paths 1977 # ?xxx/... are special absolute paths
1956 # ?random/... random maps 1978 # ?random/... random maps
1957 # /... normal maps 1979 # /... normal maps
1958 # ~user/... per-player map of a specific user 1980 # ~user/... per-player map of a specific user
1959 # !up !down for quad maps, or other maps with up/down layers
1960 1981
1961 $path =~ s/$PATH_SEP/\//go; 1982 $path =~ s/$PATH_SEP/\//go;
1962 1983
1963 # treat it as relative path if it starts with 1984 # treat it as relative path if it starts with
1964 # something that looks reasonable 1985 # something that looks reasonable
1965 if ($path =~ m{^(?:\./|\.\./|\w)}) { 1986 if ($path =~ m{^(?:\./|\.\./|\w)}) {
1966 $base or Carp::carp "normalise called with relative path and no base: '$path'"; 1987 $base or Carp::carp "normalise called with relative path and no base: '$path'";
1967 1988
1968 $base =~ s{[^/]+/?$}{}; 1989 $base =~ s{[^/]+/?$}{};
1969 $path = "$base/$path"; 1990 $path = "$base/$path";
1970
1971 } elsif ($path eq '!up') {
1972 $base && ref $base
1973 or Carp::carp "normalise called with relative tile path and no base: '$path'";
1974
1975 my $uppth = $base->tile_path (cf::TILE_UP);
1976 $path = $uppth if $uppth;
1977
1978 } elsif ($path eq '!down') {
1979 $base && ref $base
1980 or Carp::carp "normalise called with relative tile path and no base: '$path'";
1981
1982 my $dpth = $base->tile_path (cf::TILE_DOWN);
1983 $path = $dpth if $dpth;
1984 } 1991 }
1985 1992
1986 for ($path) { 1993 for ($path) {
1987 redo if s{/\.?/}{/}; 1994 redo if s{/\.?/}{/};
1988 redo if s{/[^/]+/\.\./}{/}; 1995 redo if s{/[^/]+/\.\./}{/};
2186 2193
2187 { 2194 {
2188 my $guard = cf::lock_acquire "map_data:$path"; 2195 my $guard = cf::lock_acquire "map_data:$path";
2189 2196
2190 return unless $self->valid; 2197 return unless $self->valid;
2191 return unless $self->in_memory == cf::MAP_SWAPPED; 2198 return unless $self->state == cf::MAP_SWAPPED;
2192
2193 $self->in_memory (cf::MAP_LOADING);
2194 2199
2195 $self->alloc; 2200 $self->alloc;
2196 2201
2197 $self->pre_load; 2202 $self->pre_load;
2198 cf::cede_to_tick; 2203 cf::cede_to_tick;
2221 } else { 2226 } else {
2222 $self->post_load_original 2227 $self->post_load_original
2223 if delete $self->{load_original}; 2228 if delete $self->{load_original};
2224 } 2229 }
2225 2230
2231 $self->state (cf::MAP_INACTIVE);
2232
2226 cf::cede_to_tick; 2233 cf::cede_to_tick;
2227 # now do the right thing for maps 2234 # now do the right thing for maps
2228 $self->link_multipart_objects; 2235 $self->link_multipart_objects;
2229 $self->difficulty ($self->estimate_difficulty) 2236 $self->difficulty ($self->estimate_difficulty)
2230 unless $self->difficulty; 2237 unless $self->difficulty;
2232 2239
2233 unless ($self->{deny_activate}) { 2240 unless ($self->{deny_activate}) {
2234 $self->decay_objects; 2241 $self->decay_objects;
2235 $self->fix_auto_apply; 2242 $self->fix_auto_apply;
2236 $self->update_buttons; 2243 $self->update_buttons;
2244 $self->post_load_physics;
2237 cf::cede_to_tick; 2245 cf::cede_to_tick;
2238 $self->activate; 2246 #$self->activate; # no longer activate maps automatically
2239 } 2247 }
2240 2248
2241 $self->{last_save} = $cf::RUNTIME; 2249 $self->{last_save} = $cf::RUNTIME;
2242 $self->last_access ($cf::RUNTIME); 2250 $self->last_access ($cf::RUNTIME);
2243
2244 $self->in_memory (cf::MAP_ACTIVE);
2245 } 2251 }
2246 2252
2247 $self->post_load; 2253 $self->post_load;
2248 2254
2249 1 2255 1
2292} 2298}
2293 2299
2294sub find_sync { 2300sub find_sync {
2295 my ($path, $origin) = @_; 2301 my ($path, $origin) = @_;
2296 2302
2303 # it's a bug to call this from the main context
2297 return cf::LOG cf::llevError | cf::logBacktrace, "do_find_sync" 2304 return cf::LOG cf::llevError | cf::logBacktrace, "do_find_sync"
2298 if $Coro::current == $Coro::main; 2305 if $Coro::current == $Coro::main;
2299 2306
2300 find $path, $origin 2307 find $path, $origin
2301} 2308}
2302 2309
2303sub do_load_sync { 2310sub do_load_sync {
2304 my ($map) = @_; 2311 my ($map) = @_;
2305 2312
2313 # it's a bug to call this from the main context
2306 return cf::LOG cf::llevError | cf::logBacktrace, "do_load_sync" 2314 return cf::LOG cf::llevError | cf::logBacktrace, "do_load_sync"
2307 if $Coro::current == $Coro::main; 2315 if $Coro::current == $Coro::main;
2308 2316
2309 $map->load; 2317 $map->load;
2310} 2318}
2315sub find_async { 2323sub find_async {
2316 my ($path, $origin, $load) = @_; 2324 my ($path, $origin, $load) = @_;
2317 2325
2318 $path = normalise $path, $origin; 2326 $path = normalise $path, $origin;
2319 2327
2328 print "find async $path (from $origin)\n";#d#
2329
2320 if (my $map = $cf::MAP{$path}) { 2330 if (my $map = $cf::MAP{$path}) {
2321 return $map if !$load || $map->in_memory == cf::MAP_ACTIVE; 2331 return $map if !$load || $map->linkable;
2322 } 2332 }
2323 2333
2324 $MAP_PREFETCH{$path} |= $load; 2334 $MAP_PREFETCH{$path} |= $load;
2325 2335
2326 $MAP_PREFETCHER ||= cf::async { 2336 $MAP_PREFETCHER ||= cf::async {
2385sub swap_out { 2395sub swap_out {
2386 my ($self) = @_; 2396 my ($self) = @_;
2387 2397
2388 my $lock = cf::lock_acquire "map_data:$self->{path}"; 2398 my $lock = cf::lock_acquire "map_data:$self->{path}";
2389 2399
2390 return if $self->in_memory != cf::MAP_ACTIVE; 2400 return if !$self->linkable;
2391 return if $self->{deny_save}; 2401 return if $self->{deny_save};
2392 return if $self->players; 2402 return if $self->players;
2393 2403
2394 # first deactivate the map and "unlink" it from the core 2404 # first deactivate the map and "unlink" it from the core
2395 $self->deactivate; 2405 $self->deactivate;
2396 $_->clear_links_to ($self) for values %cf::MAP; 2406 $_->clear_links_to ($self) for values %cf::MAP;
2397 $self->in_memory (cf::MAP_SWAPPED); 2407 $self->state (cf::MAP_SWAPPED);
2398 2408
2399 # then atomically save 2409 # then atomically save
2400 $self->_save; 2410 $self->_save;
2401 2411
2402 # then free the map 2412 # then free the map
2428 2438
2429 return if $self->players; 2439 return if $self->players;
2430 2440
2431 cf::trace "resetting map ", $self->path, "\n"; 2441 cf::trace "resetting map ", $self->path, "\n";
2432 2442
2433 $self->in_memory (cf::MAP_SWAPPED); 2443 $self->state (cf::MAP_SWAPPED);
2434 2444
2435 # need to save uniques path 2445 # need to save uniques path
2436 unless ($self->{deny_save}) { 2446 unless ($self->{deny_save}) {
2437 my $uniq = $self->uniq_path; utf8::encode $uniq; 2447 my $uniq = $self->uniq_path; utf8::encode $uniq;
2438 2448
2934 $Coro::current->{desc} = "enter_exit"; 2944 $Coro::current->{desc} = "enter_exit";
2935 2945
2936 unless (eval { 2946 unless (eval {
2937 $self->deactivate_recursive; # just to be sure 2947 $self->deactivate_recursive; # just to be sure
2938 2948
2939 # random map handling
2940 {
2941 my $guard = cf::lock_acquire "exit_prepare:$exit";
2942
2943 prepare_random_map $exit
2944 if $exit->slaying eq "/!";
2945 }
2946
2947 my $map = cf::map::normalise $exit->slaying, $exit->map; 2949 my $map = cf::map::normalise $exit->slaying, $exit->map;
2948 my $x = $exit->stats->hp; 2950 my $x = $exit->stats->hp;
2949 my $y = $exit->stats->sp; 2951 my $y = $exit->stats->sp;
2952
2953 # special map handling
2954 my $slaying = $exit->slaying;
2955
2956 # special map handling
2957 if ($slaying eq "/!") {
2958 my $guard = cf::lock_acquire "exit_prepare:$exit";
2959
2960 prepare_random_map $exit
2961 if $exit->slaying eq "/!"; # need to re-check after getting the lock
2962
2963 $map = $exit->slaying;
2964
2965 } elsif ($slaying eq '!up') {
2966 $map = $exit->map->tile_path (cf::TILE_UP);
2967 $x = $exit->x;
2968 $y = $exit->y;
2969
2970 } elsif ($slaying eq '!down') {
2971 $map = $exit->map->tile_path (cf::TILE_DOWN);
2972 $x = $exit->x;
2973 $y = $exit->y;
2974 }
2950 2975
2951 $self->goto ($map, $x, $y); 2976 $self->goto ($map, $x, $y);
2952 2977
2953 # if exit is damned, update players death & WoR home-position 2978 # if exit is damned, update players death & WoR home-position
2954 $self->contr->savebed ($map, $x, $y) 2979 $self->contr->savebed ($map, $x, $y)
4093 4118
4094############################################################################# 4119#############################################################################
4095 4120
4096my $bug_warning = 0; 4121my $bug_warning = 0;
4097 4122
4098our @WAIT_FOR_TICK;
4099our @WAIT_FOR_TICK_BEGIN;
4100
4101sub wait_for_tick() { 4123sub wait_for_tick() {
4102 return Coro::cede if tick_inhibit || $Coro::current == $Coro::main; 4124 return Coro::AnyEvent::poll if tick_inhibit || $Coro::current == $Coro::main;
4103 4125
4104 my $signal = new Coro::Signal; 4126 $WAIT_FOR_TICK->wait;
4105 push @WAIT_FOR_TICK, $signal;
4106 $signal->wait;
4107} 4127}
4108 4128
4109sub wait_for_tick_begin() { 4129sub wait_for_tick_begin() {
4110 return Coro::cede if tick_inhibit || $Coro::current == $Coro::main; 4130 return Coro::AnyEvent::poll if tick_inhibit || $Coro::current == $Coro::main;
4111 4131
4112 my $signal = new Coro::Signal; 4132 my $signal = new Coro::Signal;
4113 push @WAIT_FOR_TICK_BEGIN, $signal; 4133 push @WAIT_FOR_TICK_BEGIN, $signal;
4114 $signal->wait; 4134 $signal->wait;
4115} 4135}
4119 Carp::cluck "major BUG: server tick called outside of main coro, skipping it" 4139 Carp::cluck "major BUG: server tick called outside of main coro, skipping it"
4120 unless ++$bug_warning > 10; 4140 unless ++$bug_warning > 10;
4121 return; 4141 return;
4122 } 4142 }
4123 4143
4124 cf::server_tick; # one server iteration 4144 cf::one_tick; # one server iteration
4125 4145
4126 #for(1..3e6){} AE::now_update; $NOW=AE::now; # generate load #d# 4146 #for(1..3e6){} AE::now_update; $NOW=AE::now; # generate load #d#
4127 4147
4128 if ($NOW >= $NEXT_RUNTIME_WRITE) { 4148 if ($NOW >= $NEXT_RUNTIME_WRITE) {
4129 $NEXT_RUNTIME_WRITE = List::Util::max $NEXT_RUNTIME_WRITE + 10, $NOW + 5.; 4149 $NEXT_RUNTIME_WRITE = List::Util::max $NEXT_RUNTIME_WRITE + 10, $NOW + 5.;
4135 } 4155 }
4136 4156
4137 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) { 4157 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) {
4138 $sig->send; 4158 $sig->send;
4139 } 4159 }
4140 while (my $sig = shift @WAIT_FOR_TICK) { 4160 $WAIT_FOR_TICK->broadcast;
4141 $sig->send;
4142 }
4143 4161
4144 $LOAD = ($NOW - $TICK_START) / $TICK; 4162 $LOAD = ($NOW - $TICK_START) / $TICK;
4145 $LOADAVG = $LOADAVG * 0.75 + $LOAD * 0.25; 4163 $LOADAVG = $LOADAVG * 0.75 + $LOAD * 0.25;
4146 4164
4147 if (0) { 4165 if (0) {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines