A player thread may sleep on input or output, except:
(1) While it is executing a C_MOD command, it may only sleep on input.
(2) While it is being aborted by the update or shutdown, it may not
sleep at all.
To find out whether a player thread may sleep on input, code has to
check condition (2). It needs do to that in recvclient().
To find out whether it may sleep on output, it has to check both
conditions. It needs to do that in pr_player() and upr_player().
The code tracked condition (1) in global variable play_lock_wanted.
It checked condition (2) by examining struct player member command.
Replace all that by new struct player member may_sleep. Initialize it
in player_new(), update it in dispatch(), shutdwn() and update_run().
This makes the tests in recvclient(), pr_player() and upr_player()
obvious. play_wrlock_wanted() is now unused, remove it.
Player threads may only sleep under certain conditions. In
particular, they must not sleep while a command is being aborted by
the update or shutdown.
io.c should not know about that. Yet io_output_all() does, because it
needs to give up when update or shutdown interrupt it. The function
was introduced in Empire 2, but it didn't give up then. Fixed in
commit a7fa7dee, v4.2.22. The fix dragged unwanted knowledge of
command abortion into io.c.
To clean up this mess, io_output_all() has to go.
First user is io_write(). io_write() automatically flushes the queue.
In wait-mode, it calls io_output_all() when the queue is longer than
the bufsize, to attempt flushing the queue completely. In
no-wait-mode, it calls io_output() every bufsize bytes. Except the
test for that is screwy, so it actually misses some of the flush
conditions.
The automatic flush makes io_write() differ from io_gets(), which is
ugly. It wasn't present in BSD Empire 1.1. Remove it again, dropping
io_write()'s last argument.
Flush the queue in its callers pr_player() and upr_player() instead.
Provide new io_output_if_queue_long() for them. Requires new struct
iop member last_out to keep track of queue growth. pr_player() and
upr_player() call repeatedly until it makes no more progress. This
flushes a bit less eagerly in wait-mode, and a bit more eagerly in
non-wait mode.
Second user is recvclient(). It needs to flush the queue before
potentially sleeping in io_input(). Do that with a simple loop around
io_output(). No functional change there.
This reverts commit fee8ac9d8f.
These *are* called while player->aborted. Could be avoided, but: the
reason for not wanting to prompt then is to have each prompt consume a
line of input. That's actually not feasible, because when we wait for
an argument (after prompting for it) when the update aborts commands,
we can't consume the argument we prompted for.
(update_run): Set it.
Replace incorrect uses of update_pending by update_running, fixing
buggy behavior while the update was trying to gain control:
(sct_do_upd_mob, shp_do_upd_mob, lnd_do_upd_mob, pln_do_upd_mob):
MOB_ACCESS mobility update was skipped.
(telegram_is_new): Fix recognition of new telegrams by timestamp.
(wu): Bulletins got misfiled as production reports.
(shp_nav): Sail path got ignored.
(setrel): Declaration of war failed silently with SLOW_WAR enabled.
Messages got suppressed.
(PR, mpr): Messages got misdirected to bulletins.
(shutdown_initiate): New.
(shut): Use it. Shutdown in zero minutes no longer cancels the
shutdown, it just works. Use negative argument to cancel. Logging is
less detailed.
(shutdown_sequence): Internal linkage.
(pr_wall): All callers prefix text it with the same header. Move it
into the function.
other. Ensure headers in include/ can be included in any order
(except for econfig-spec.h, which is special). New header types.h to
help avoid inclusion cycles. Sort include directives. Remove some
superflous includes.
called with a null prompt when it is believed not to use it, and that
belief is sometimes wrong. Other users could have similar bugs. Some
systems (GNU, Windows) deal gracefully with printing null strings,
others crash.
(prxy, border, ac_encounter, look, budg): Fix misuse of pr() and PR():
passed formatted string instead of format string and arguments.
Correctness depends on argument values and tables not containing '%',
which is correct, but fragile.
is unsafe! By the time the blocked thread wakes up, that player may
be gone, along with its struct iop *, and io_write() follows a
dangling pointer. Moreover, at most one thread may use empth_select()
on the same file descriptor. Violations of that restriction cause
threads to hang under Windows since ntthread.c rev. 1.15. Make all
output to another player non-blocking for now. Historically, player
threads sent output only to their socket, though their own iop. This
was broken by flash and asynchronous telegram notification a long time
ago.
(copy_utf8_to_ascii_no_funny): New.
(flash, wall, prmptrd, uprmptrd, getcommand): Use them to filter
input.
(uprnf, pr_flash): Use them to filter output.
(prtoascii): No longer used, remove.
(player_commands, player_commands_index): Internal linkage.
(player): New member flags.
(PF_UTF8, NF_UTF8): New PF_UTF8 replaces NF_UTF8. Users changed.
(options_cmd): New.
(login_coms): New command `options'.
(toggle): Revert to the previous rev.
(NF_UTF8, togg): New client flag.
(flash, wall): User text input filtering.
(parse, prmptrd): Normal text input filtering.
(uprmptrd, ugetstring): New, to get user text.
(getele, flash, wall): Use them.
(getele): No need to filter out funny characters; input filtering
takes care of them.
(sendmessage, ufindbreak): Work on user text.
(uprnf): New, to print user text.
(rea, gamedown, show_motd): Use it.
(prnf): Unused, remove.
(pr, upr_player): Normal text output filtering (with highlighting).
(pr_flash): User text output filtering.