client: Unbreak standalone build
[empserver] / doc / threads
1
2 The game has been threaded.  Major changes have occurred.
3 Emp_update, emp_login, emp_tm, and emp_player have been merged.
4 Basically, there isn't anything else besides server.  It's big.
5 60,000-lines of code big.
6
7 The lib directory now contains nine subdirectories:
8         common 
9         gen
10         global
11         as
12         player
13         commands
14         subs
15         update
16         lwp
17
18 The main directory contains five (code) directories:
19         client
20         lib
21         server
22         util
23         h
24
25 The server has seven basic threads:
26
27         main:
28                 creates accept, killidle, and update scheduler.
29                 sets signals, opens files.
30         accept:
31                 opens a socket, binds, listens, and accepts new players.
32                 creates a player thread for each new socket.
33         player:
34                 negotaties the player's login, and then interprets
35                 the player's game commands.
36         killidle:
37                 eyeballs the logged-in players every sixty seconds and
38                 closes the connections of those who have been idle for
39                 longer than 15 minutes.
40         update scheduler:
41                 Sleeps until update is due to go off, then instructs all
42                 player threads currently running commands to abort them.
43                 It waits for a few seconds so that this can occur, and
44                 then creates the update thread, and schedules the next
45                 update.  (This scheduler should produce single, accurate
46                 updates instead of double-updates and delayed updates)
47         update:
48                 The standard update procedure.  It runs at high priority
49                 and performs no network i/o, so the game effectively hangs
50                 while the update is in progress.
51         select:
52                 This thread and its interface provides a mechanism for
53                 other threads to deschedule until either a file descriptor
54                 is read/write ready, or a particular amount of time has passed.
55                 When the select thread actually runs, the whole process
56                 blocks until the select system call returns.  However,
57                 select runs at the lowest possible priority so other
58                 threads get to run to completion before the select gets
59                 executed.
60
61 Overall Notes:
62
63         Unit and sector files are kept in-core for Your Viewing Pleasure.
64         (It was actually required in order to merge in emp_update)
65         This means the server will use significant memory for the larger
66         games.
67
68         Per-player bigmap files have been merged into one EF_MAP file, with
69         each player getting one record.  This is also kept in-core.
70
71         Estimated memory cost of a 64-player 256x256 world game with
72         each player having 100 land units, 100 planes, 100 ships, and
73         a bigmap comes to a little over eleven megabytes of space,
74         including the 700k text segment.
75
76         the "wai()" command doesn't work yet.
77
78 Implementation Notes: My Opportunity to Spout Empire Technical Jargon
79
80         Empire is now a miniature operating system, with all that entails.
81         Threads are not simple to use.  I know the threads package
82         intimately, and I was confused several times -- probably because
83         the threads interface I provide isn't all that straightforward,
84         even though it seems like it.  Hopefully a second iteration by
85         someone who knows what they're doing will be better.
86
87         I expect this will be much worse for everyone else who hasn't gone
88         through my experience.  Bottom line for all you part-time hackers
89         out there: don't mess with the current process model, or you'll get
90         yourself into all kinds of trouble.
91
92         Thread scheduling and descheduling happens in the io_input and
93         io_output calls.  The higher level interfaces in the player thread
94         to these are the getstarg/getstring and pr procedures.  If your
95         process ever has to wait for input or output, it will block, allowing
96         other threads to run.  Those other threads may well modify data
97         out from under you, so be prepared to have your shared in-memory
98         constructs (ships, planes, sectors, land units, etc) modified out
99         from under you whenever you do i/o.
100
101         There's a new player global context structure that is shared
102         amongst all the player threads.  When a given thread starts
103         or restarts, it sets the global player variable to the appropriate
104         value.  Thus, part of the logic of a "context switch" is the setting
105         of player.  If you go and add calls to the lightweight process
106         system, you *must* be sure to set the player variable as the
107         io_output and io_input routines do.  Otherwise, things will be
108         extremely confused.  (I'm not very happy with this global
109         variable, but I didn't have the gumption to do anything more)
110
111         Most routines that used to return pointers to static space no
112         longer do so.  Instead, you're expected to pass in a buffer which
113         will be filled up by the routine.  This hit a *lot* of routines,
114         so check the new syntax before using an old and trusted routine
115         blindly.
116
117         Any files that are loaded into core (like the sector, map, nation,
118         ship, plane, and land unit files) are shared between all the threads.
119         That's good news.  If your thread modifies another player's nat_tgms
120         field, he'll see it next time through the command loop, without
121         anyone having to read anything from disk!  Furthermore, he'll have
122         no delay in zeroing out that field, so there won't be the annoying
123         double telegram reports which were caused by the delay induced by
124         emp_tm.
125
126         Unfortunately, modifications to entries to these mapped files must
127         be followed by the appropriate "write record" command (like putship,
128         putnat, etc) or else the changes won't be stored to disk permanently.
129         Update is the exception to this rule, because it writes all records
130         to disk using ef_flush when it's done.  This is important, since
131         if and when the players learn how to coredump the server *and* they've
132         managed to build some object w/o their nation record having been
133         updated, they essentially get the item without paying for it.
134
135         There are two interfaces to the empire file code: the pointer
136         interface exemplified by np = getnatp(cnum), and the copy interface
137         shown by getsect(x, y, &sect)/putsect(&sect).  Both still work fine.
138         However, you have to be careful when using the pointer interface
139         not to change things prematurely, because any changes to the pointer
140         actually change the data itself -- including putvar, etc.  Some
141         commands use the copy interface now, change some variables, and
142         then decide to bail out of the command when something goes wrong.
143         Be careful if you decide to use pointers and then bail out early.
144         Even if *you* don't write the pointer to disk, other subsequent
145         activity probably *will*, resulting in a surprise for the players.
146
147         Each player thread gets 64k of stack space + more depending on the
148         size of WORLD_X*WORLD_Y.  I hope that's enough.  If not, we'll have
149         to remove the larger stack variables and move them into static space.
150
151         Adding new records to core-loaded (EFF_MEM) files is annoying now.
152         Instead of simply writing out a new record, you have to call
153         ef_extend(type, count) to enlarge the file by count records.
154         Additionally, any outstanding pointers you obtained from that
155         file are now invalid.  This command results in a "close/open"
156         for the file, requiring the entire contents to be read in from
157         disk again.  Luckily, the only instance I saw of this was the
158         "build" command, and my call to ef_extend does it in groups of
159         fifty.
160
161 Dave