--- deliantra/server/lib/cf.pm 2007/01/13 23:32:43 1.167 +++ deliantra/server/lib/cf.pm 2007/01/14 22:14:35 1.176 @@ -10,7 +10,7 @@ use Safe; use Safe::Hole; -use Coro 3.3 (); +use Coro 3.4 (); use Coro::Event; use Coro::Timer; use Coro::Signal; @@ -46,6 +46,8 @@ our $TICK = MAX_TIME * 1e-6; our $TICK_WATCHER; +our $AIO_POLL_WATCHER; +our $WRITE_RUNTIME_WATCHER; our $NEXT_TICK; our $NOW; @@ -259,7 +261,11 @@ sub freeze_mainloop { return unless $TICK_WATCHER->is_active; - my $guard = Coro::guard { $TICK_WATCHER->start }; + my $guard = Coro::guard { + $TICK_WATCHER->start; + $WRITE_RUNTIME_WATCHER->start; + }; + $WRITE_RUNTIME_WATCHER->stop; $TICK_WATCHER->stop; $guard } @@ -340,8 +346,6 @@ } sub write_runtime { - return unless $TICK_WATCHER->is_active; - my $runtime = cf::localdir . "/runtime"; my $fh = aio_open "$runtime~", O_WRONLY | O_CREAT, 0644 @@ -501,6 +505,12 @@ my %attachment; +sub cf::attachable::thawer_merge { + # simply override everything except _meta + local $_[0]{_meta}; + %{$_[0]} = %{$_[1]}; +} + sub _attach_cb($$$$) { my ($registry, $event, $prio, $cb) = @_; @@ -682,6 +692,8 @@ # basically do the same as instantiate, without calling instantiate my ($obj) = @_; + bless $obj, ref $obj; # re-bless in case extensions have been reloaded + my $registry = $obj->registry; @$registry = (); @@ -1103,7 +1115,8 @@ use Coro::AIO; use overload - '""' => \&as_string; + '""' => \&as_string, + fallback => 1; our $MAX_RESET = 3600; our $DEFAULT_RESET = 3000; @@ -1140,6 +1153,18 @@ # also paths starting with '/' $EXT_MAP{"cf::map"} = qr{^(?=/)}; +sub thawer_merge { + my ($self, $merge) = @_; + + # we have to keep some variables in memory intact + local $self->{path}; + local $self->{load_path}; + local $self->{deny_save}; + local $self->{deny_reset}; + + $self->SUPER::thawer_merge ($merge); +} + sub normalise { my ($path, $base) = @_; @@ -1245,8 +1270,8 @@ my ($self) = @_; utf8::encode (my $save = $self->save_path); - IO::AIO::aioreq_pri 4; IO::AIO::aio_unlink $save; - IO::AIO::aioreq_pri 4; IO::AIO::aio_unlink "$save.pst"; + IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink $save; + IO::AIO::aioreq_pri 4; Coro::AIO::aio_unlink "$save.pst"; } sub load_header_from($) { @@ -1317,6 +1342,7 @@ or return; if ($map->should_reset) { + $cf::WAIT_FOR_TICK->wait; $map->reset; undef $guard; $map = find $path @@ -1496,7 +1522,7 @@ my ($self) = @_; # TODO: safety, remove and allow resettable per-player maps - return 1e99 if $self->isa ("ext::map_per_player"); + return 1e99 if $self->isa ("ext::map_per_player");#d# return 1e99 if $self->{deny_reset}; my $time = $self->fixed_resettime ? $self->{instantiate_time} : $self->last_access; @@ -1511,20 +1537,6 @@ $self->reset_at <= $cf::RUNTIME } -sub rename { - my ($self, $new_path) = @_; - - normalise $new_path; - - $self->unlink_save; - - delete $cf::MAP{$self->path}; - $self->{path} = $new_path; $self->path ($self->{path}); - $cf::MAP{$self->path} = $self; - - $self->save; -} - sub reset { my ($self) = @_; @@ -1551,9 +1563,18 @@ sub nuke { my ($self) = @_; + delete $cf::MAP{$self->path}; + + $self->unlink_save; + + bless $self, "cf::map"; + delete $self->{deny_reset}; $self->{deny_save} = 1; $self->reset_timeout (1); - $self->rename ("{nuke}/" . ($nuke_counter++)); + $self->path ($self->{path} = "{nuke}/" . ($nuke_counter++)); + + $cf::MAP{$self->path} = $self; + $self->reset; # polite request, might not happen } @@ -2209,7 +2230,9 @@ # 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# - async { Event::one_event }; + (async { + Event::one_event; + })->prio (Coro::PRIO_MAX); }; cfg_load; @@ -2367,13 +2390,21 @@ warn "reloaded"; }; +our $RELOAD_WATCHER; # used only during reload + register_command "reload" => sub { my ($who, $arg) = @_; if ($who->flag (FLAG_WIZ)) { - $who->message ("start of reload."); - reload; - $who->message ("end of reload."); + $who->message ("reloading server."); + + # doing reload synchronously and two reloads happen back-to-back, + # coro crashes during coro_state_free->destroy here. + + $RELOAD_WATCHER ||= Event->timer (after => 0, data => WF_AUTOCANCEL, cb => sub { + reload; + undef $RELOAD_WATCHER; + }); } }; @@ -2404,7 +2435,7 @@ IO::AIO::max_poll_time $TICK * 0.2; -Event->io ( +$AIO_POLL_WATCHER = Event->io ( fd => IO::AIO::poll_fileno, poll => 'r', prio => 5, @@ -2412,7 +2443,7 @@ cb => \&IO::AIO::poll_cb, ); -Event->timer ( +$WRITE_RUNTIME_WATCHER = Event->timer ( data => WF_AUTOCANCEL, after => 0, interval => 10,