Skip to content
Niklas Lindholm edited this page Nov 25, 2016 · 2 revisions

Here are some notes on how NiKom is working internally. It will probably need to be expanded over time..

A NiKom system can handle several "nodes" at the same time where each node can have a user online and interacting with the system. It also contains an ARExx interface that can be used simultaneously. These parts communicate with each other mainly through a large shared memory block. The file NiKomStr.h contains the definition to the main structure called "System". In code it's usually referred to as "Servermem".

NiKServer

The server is not so much a server in the traditional sense since there are many shared resources that the nodes access directly. It's main responsibilities are

  • Allocate the shared memory structure and initialize it from various data files on disk.
  • Receive commands from the nodes to perform certain tasks like saving a new text or tell the system that a new node is starting to run. For this an exec message port called "NiKomPort" is used.
  • Coordinate the original style of synchronization when race conditions need to be avoided (e.g. when writing to data files on disk) See more about this below.
  • Receive requests from ARexx when NiKom function calls are made.

Synchronization

Originally there was only one way to perform synchronization and it was basically based on the running thread of the server. When a node wanted to get exclusive access it would call the function NiKForbid(). It would send a FORBID message to the server which would in turn wait for a message on a special "permit port" called "NiKomPermit". Until the node sent a message to the permit port it would have exclusive access. No other node would be able to get it since the server wasn't at the moment receiving messages on the normal port and the server couldn't do anything (like executing an ARexx function) since it was blocked on the permit port. And when the server was doing anything else than listening to its port no node would be able to do a forbid.

This is a pretty coarse grained and crude way of doing things but it was working pretty well even for systems like Datormagazin BBS with 8-10 running nodes. The names "forbid" and "permit" come from the system calls in AmigaOS that would disable and re-enable multitasking. The NiKom forbid and permit is however not doing that. They are just named similarly.

Then at some point I realized what that "Semaphores" chapter in the Rom Kernel Manuals was all about and some more fine grained semaphores in Servermem were introduced. They have not been fully used yet though so most synchronization is still using NiKForbid() and NiKPermit(). Room for improvement.

NiKomCon/NiKomSer

NiKomCon and NiKomSer are the two different node types that runs the login sessions for users. They have a mostly shared code base with e.g. IO functions being implemented differently for the two.

The function connection() in NiKFuncs.c can be seen as the starting point for the shared code base. It is called when the user has successfully entered username and password and is being let into the system. When the program returns from connection() the user is logged out.

The main command loop and the KOM "engine" was completely re-written at the end of 2015. If you have tried to read the code before this and gave up before it was so complicated you will hopefully find it nicer now!

At the end of connection() the function KomLoop() is called. This is the main command loop that serves as the engine of the KOM interface. It has a simple loop that will go on until the user should be logged out (either because the user wants to or because the user is forced to). It will first figure out what the default command should be (the one that is displayed in the prompt) and then display the prompt and let the user enter a command.

At some point the function DoExecuteCommand() will be called that will actually execute a command (either as typed by the user or from the default command). This is a big switch statement that calls the right command function. The format of a command function is, from now on:

void Cmd_MyCommand(void);

The command function is responsible, whenever it does any kind of user IO, to check whether the user should be logged out (either by checking return values of the IO functions or by calling ImmediateLogout()) and in this case return as fast as possible. Legacy command functions have different names and also typically return certain (sometimes magic..) values to indicate why it is returning. This is not necessary anymore. The return value is not ignored.

Clone this wiki locally