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.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 }
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}
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
2328 print "find async $path (from $origin)\n";#d#
2329
2305 if (my $map = $cf::MAP{$path}) { 2330 if (my $map = $cf::MAP{$path}) {
2306 return $map if !$load || $map->in_memory == cf::MAP_ACTIVE; 2331 return $map if !$load || $map->linkable;
2307 } 2332 }
2308 2333
2309 $MAP_PREFETCH{$path} |= $load; 2334 $MAP_PREFETCH{$path} |= $load;
2310 2335
2311 $MAP_PREFETCHER ||= cf::async { 2336 $MAP_PREFETCHER ||= cf::async {
2370sub swap_out { 2395sub swap_out {
2371 my ($self) = @_; 2396 my ($self) = @_;
2372 2397
2373 my $lock = cf::lock_acquire "map_data:$self->{path}"; 2398 my $lock = cf::lock_acquire "map_data:$self->{path}";
2374 2399
2375 return if $self->in_memory != cf::MAP_ACTIVE; 2400 return if !$self->linkable;
2376 return if $self->{deny_save}; 2401 return if $self->{deny_save};
2377 return if $self->players; 2402 return if $self->players;
2378 2403
2379 # first deactivate the map and "unlink" it from the core 2404 # first deactivate the map and "unlink" it from the core
2380 $self->deactivate; 2405 $self->deactivate;
2381 $_->clear_links_to ($self) for values %cf::MAP; 2406 $_->clear_links_to ($self) for values %cf::MAP;
2382 $self->in_memory (cf::MAP_SWAPPED); 2407 $self->state (cf::MAP_SWAPPED);
2383 2408
2384 # then atomically save 2409 # then atomically save
2385 $self->_save; 2410 $self->_save;
2386 2411
2387 # then free the map 2412 # then free the map
2413 2438
2414 return if $self->players; 2439 return if $self->players;
2415 2440
2416 cf::trace "resetting map ", $self->path, "\n"; 2441 cf::trace "resetting map ", $self->path, "\n";
2417 2442
2418 $self->in_memory (cf::MAP_SWAPPED); 2443 $self->state (cf::MAP_SWAPPED);
2419 2444
2420 # need to save uniques path 2445 # need to save uniques path
2421 unless ($self->{deny_save}) { 2446 unless ($self->{deny_save}) {
2422 my $uniq = $self->uniq_path; utf8::encode $uniq; 2447 my $uniq = $self->uniq_path; utf8::encode $uniq;
2423 2448
2931 # special map handling 2956 # special map handling
2932 if ($slaying eq "/!") { 2957 if ($slaying eq "/!") {
2933 my $guard = cf::lock_acquire "exit_prepare:$exit"; 2958 my $guard = cf::lock_acquire "exit_prepare:$exit";
2934 2959
2935 prepare_random_map $exit 2960 prepare_random_map $exit
2936 if $slaying eq "/!"; # need to re-check after getting the lock 2961 if $exit->slaying eq "/!"; # need to re-check after getting the lock
2962
2963 $map = $exit->slaying;
2937 2964
2938 } elsif ($slaying eq '!up') { 2965 } elsif ($slaying eq '!up') {
2939 $map = $exit->map->tile_path (cf::TILE_UP); 2966 $map = $exit->map->tile_path (cf::TILE_UP);
2940 $x = $exit->x; 2967 $x = $exit->x;
2941 $y = $exit->y; 2968 $y = $exit->y;
4091 4118
4092############################################################################# 4119#############################################################################
4093 4120
4094my $bug_warning = 0; 4121my $bug_warning = 0;
4095 4122
4096our @WAIT_FOR_TICK;
4097our @WAIT_FOR_TICK_BEGIN;
4098
4099sub wait_for_tick() { 4123sub wait_for_tick() {
4100 return Coro::cede if tick_inhibit || $Coro::current == $Coro::main; 4124 return Coro::AnyEvent::poll if tick_inhibit || $Coro::current == $Coro::main;
4101 4125
4102 my $signal = new Coro::Signal; 4126 $WAIT_FOR_TICK->wait;
4103 push @WAIT_FOR_TICK, $signal;
4104 $signal->wait;
4105} 4127}
4106 4128
4107sub wait_for_tick_begin() { 4129sub wait_for_tick_begin() {
4108 return Coro::cede if tick_inhibit || $Coro::current == $Coro::main; 4130 return Coro::AnyEvent::poll if tick_inhibit || $Coro::current == $Coro::main;
4109 4131
4110 my $signal = new Coro::Signal; 4132 my $signal = new Coro::Signal;
4111 push @WAIT_FOR_TICK_BEGIN, $signal; 4133 push @WAIT_FOR_TICK_BEGIN, $signal;
4112 $signal->wait; 4134 $signal->wait;
4113} 4135}
4117 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"
4118 unless ++$bug_warning > 10; 4140 unless ++$bug_warning > 10;
4119 return; 4141 return;
4120 } 4142 }
4121 4143
4122 cf::server_tick; # one server iteration 4144 cf::one_tick; # one server iteration
4123 4145
4124 #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#
4125 4147
4126 if ($NOW >= $NEXT_RUNTIME_WRITE) { 4148 if ($NOW >= $NEXT_RUNTIME_WRITE) {
4127 $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.;
4133 } 4155 }
4134 4156
4135 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) { 4157 if (my $sig = shift @WAIT_FOR_TICK_BEGIN) {
4136 $sig->send; 4158 $sig->send;
4137 } 4159 }
4138 while (my $sig = shift @WAIT_FOR_TICK) { 4160 $WAIT_FOR_TICK->broadcast;
4139 $sig->send;
4140 }
4141 4161
4142 $LOAD = ($NOW - $TICK_START) / $TICK; 4162 $LOAD = ($NOW - $TICK_START) / $TICK;
4143 $LOADAVG = $LOADAVG * 0.75 + $LOAD * 0.25; 4163 $LOADAVG = $LOADAVG * 0.75 + $LOAD * 0.25;
4144 4164
4145 if (0) { 4165 if (0) {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines