--- deliantra/server/lib/cf.pm 2007/01/04 17:28:49 1.134 +++ deliantra/server/lib/cf.pm 2007/01/05 20:04:02 1.140 @@ -28,7 +28,7 @@ # work around bug in YAML::Syck - bad news for perl6, will it be as broken wrt. unicode? $YAML::Syck::ImplicitUnicode = 1; -$Coro::main->prio (2); # run main coroutine ("the server") with very high priority +$Coro::main->prio (Coro::PRIO_MAX); # run main coroutine ("the server") with very high priority sub WF_AUTOCANCEL () { 1 } # automatically cancel this watcher on reload @@ -181,28 +181,6 @@ JSON::Syck::Dump $_[0] } -=item my $guard = cf::guard { BLOCK } - -Run the given callback when the guard object gets destroyed (useful for -coroutine cancellations). - -You can call C<< ->cancel >> on the guard object to stop the block from -being executed. - -=cut - -sub guard(&) { - bless \(my $cb = $_[0]), cf::guard::; -} - -sub cf::guard::cancel { - ${$_[0]} = sub { }; -} - -sub cf::guard::DESTROY { - ${$_[0]}->(); -} - =item cf::lock_wait $string Wait until the given lock is available. See cf::lock_acquire. @@ -210,7 +188,7 @@ =item my $lock = cf::lock_acquire $string Wait until the given lock is available and then acquires it and returns -a guard object. If the guard object gets destroyed (goes out of scope, +a Coro::guard object. If the guard object gets destroyed (goes out of scope, for example when the coroutine gets canceled), the lock is automatically returned. @@ -239,36 +217,30 @@ $LOCK{$key} = []; - cf::guard { + Coro::guard { # wake up all waiters, to be on the safe side $_->ready for @{ delete $LOCK{$key} }; } } -=item cf::async { BLOCK } - -Like C, but runs the given BLOCK in an eval and only logs the -error instead of exiting the server in case of a problem. - -=cut - -sub async(&) { - my ($cb) = @_; - - Coro::async { - eval { $cb->() }; - warn $@ if $@; - } -} - sub freeze_mainloop { return unless $TICK_WATCHER->is_active; - my $guard = guard { $TICK_WATCHER->start }; + my $guard = Coro::guard { $TICK_WATCHER->start }; $TICK_WATCHER->stop; $guard } +=item cf::async { BLOCK } + +Currently the same as Coro::async_pool, meaning you cannot use +C, C or other gimmicks on these coroutines. The only +thing you are allowed to do is call C on it. + +=cut + +BEGIN { *async = \&Coro::async_pool } + =item cf::sync_job { BLOCK } The design of crossfire+ requires that the main coro ($Coro::main) is @@ -296,15 +268,17 @@ my $busy = 1; my @res; - (Coro::async { + (async { @res = eval { $job->() }; warn $@ if $@; undef $busy; })->prio (Coro::PRIO_MAX); while ($busy) { - Coro::cede_notself; - Event::one_event unless Coro::nready; + unless (Coro::cede) { + Coro::nready ? Event::one_event 0 : Event::one_event; + Coro::cede_notself unless Coro::cede; + } } wantarray ? @res : $res[0] @@ -315,17 +289,17 @@ } } -=item $coro = cf::coro { BLOCK } +=item $coro = cf::async_ext { BLOCK } -Creates and returns a new coro. This coro is automcatially being canceled -when the extension calling this is being unloaded. +Like async, but this coro is automcatially being canceled when the +extension calling this is being unloaded. =cut -sub coro(&) { +sub async_ext(&) { my $cb = shift; - my $coro = &cf::async ($cb); + my $coro = &Coro::async ($cb); $coro->on_destroy (sub { delete $EXT_CORO{$coro+0}; @@ -1186,6 +1160,9 @@ my $map = cf::map::new or return; + # for better error messages only, will be overwritten + $map->path ($path); + $map->load_header ($path) or return; @@ -1317,6 +1294,8 @@ sub save { my ($self) = @_; + my $lock = cf::lock_acquire "map_data:" . $self->path; + $self->{last_save} = $cf::RUNTIME; return unless $self->dirty; @@ -1344,6 +1323,8 @@ # save first because save cedes $self->save; + my $lock = cf::lock_acquire "map_data:" . $self->path; + return if $self->players; return if $self->in_memory != cf::MAP_IN_MEMORY; return if $self->{deny_save}; @@ -1395,6 +1376,8 @@ sub reset { my ($self) = @_; + my $lock = cf::lock_acquire "map_data:" . $self->path; + return if $self->players; return if $self->{path}{user_rel};#d# @@ -1569,27 +1552,32 @@ # try to abort aborted map switching on player login :) # should happen only on crashes if ($pl->ob->{_link_pos}) { + $pl->ob->enter_link; - cf::async { + (async { # we need this sleep as the login has a concurrent enter_exit running # and this sleep increases chances of the player not ending up in scorn + $pl->ob->reply (undef, + "There was an internal problem at your last logout, " + . "the server will try to bring you to your intended destination in a second.", + cf::NDI_RED); Coro::Timer::sleep 1; $pl->ob->leave_link; - }; + })->prio (2); } }, ); -=item $player_object->goto_map ($path, $x, $y) +=item $player_object->goto ($path, $x, $y) =cut -sub cf::object::player::goto_map { +sub cf::object::player::goto { my ($self, $path, $x, $y) = @_; $self->enter_link; - (cf::async { + (async { $path = new cf::path $path; my $map = cf::map::find $path->as_string; @@ -1661,14 +1649,14 @@ $self->enter_link; - (cf::async { + (async { $self->deactivate_recursive; # just to be sure unless (eval { prepare_random_map $exit if $exit->slaying eq "/!"; my $path = new cf::path $exit->slaying, $exit->map && $exit->map->path; - $self->goto_map ($path, $exit->stats->hp, $exit->stats->sp); + $self->goto ($path, $exit->stats->hp, $exit->stats->sp); 1; }) { @@ -1752,7 +1740,7 @@ }, ); -=item $client->coro (\&cb) +=item $client->async (\&cb) Create a new coroutine, running the specified callback. The coroutine will be automatically cancelled when the client gets destroyed (e.g. on logout, @@ -1760,10 +1748,10 @@ =cut -sub cf::client::coro { +sub cf::client::async { my ($self, $cb) = @_; - my $coro = &cf::async ($cb); + my $coro = &Coro::async ($cb); $coro->on_destroy (sub { delete $self->{_coro}{$coro+0}; @@ -2011,6 +1999,9 @@ $EMERGENCY_POSITION = $CFG{emergency_position} || ["/world/world_105_115", 5, 37]; + $cf::map::MAX_RESET = $CFG{map_max_reset} if exists $CFG{map_max_reset}; + $cf::map::DEFAULT_RESET = $CFG{map_default_reset} if exists $CFG{map_default_reset}; + if (exists $CFG{mlockall}) { eval { $CFG{mlockall} ? &mlockall : &munlockall @@ -2024,9 +2015,7 @@ # we must not ever block the main coroutine local $Coro::idle = sub { Carp::cluck "FATAL: Coro::idle was called, major BUG, use cf::sync_job!\n";#d# - (Coro::unblock_sub { - Event::one_event; - })->(); + async { Event::one_event }; }; cfg_load;