8

Related to another question about CLOCK$ device name, I began to wonder if and how this device was actually used in MS-DOS. I have seen some references how to specify a clock driver when creating a DOS driver, but was there ever any software that would access the CLOCK$ device file directly, or did DOS do any operations on the file itself internally?

I think there could be some internal hooks that would use whatever functions provided by a clock driver installed to the system, but I'm more interested if there was any use for the device file directly, and if not, why it was exposed to the file system?

For other driver files, such as CON, LPTx and COMx, the usage via opening the file and reading/writing was straightforward and possible, while probably not that common especially for software supporting printers or serial communication in particular (due to lack of interrupt support and configuration options etc).

2 Answers 2

10

There are no hooks, all usage of the clock device goes through documented device driver interfaces. Clock drivers do get their own attribute in the attribute header, but that was documented too.

During initialisation, DOS finds the clock device driver by looking for a character device with bit 3 (clock driver) set in the device attributes. It keeps a pointer to this driver (BCLOCK in the published MS-DOS 2 source code) and uses that whenever it needs to invoke the clock driver, via the READTIME procedure and the SET_TIME system call (DOS never sets the time itself).

DOS uses this driver to retrieve the date and time whenever necessary, as determined by whatever device the driver is written for. It does so by reading from the device, using the standard character device interface; the driver is supposed to return six bytes, encoding the date (as days since January 1, 1980 over two bytes), the minutes, hours, seconds and hundredths of seconds:

Byte 0 Byte 1 Byte 2 Byte 3 Byte 4 Byte 5
Days since January 1, 1980 (low byte) Days (high byte) Minutes Hours Hundredths Seconds

This includes whenever the DOS date and time are retrieved (interrupt 0x21, services 0x2A and 0x2C).

Whenever the DOS date or time is set (interrupt 0x21, services 0x2B and 0x2D), DOS writes to the device to update the stored date and time, again using the standard character device interface.

I'm more interested if there was any use for the device file directly, and if not, why it was exposed to the file system?

In practice there was no need for programs to access the clock device directly, since DOS provided its own API to access it; but I imagine some programs did (at least, example programs showing how the interface works; but probably no non-toy program, apart from Windows’ virtual timer device). Note that there is one significant difference between access through the DOS date/time APIs and the DOS device APIs: the former uses the current clock driver identified by the relevant attribute bit, the latter uses the first driver matching the name used to open the device.

The driver needed a name because it was a regular character device driver, and all such drivers have names. The reason for making the clock driver a regular device driver is so that it can be easily replaced. There’s a nice example of a replacement driver in the Waite Group’s Writing MS-DOS Device Drivers.

11
  • Are you sure it's only done during initialisation (boot)?
    – Raffzahn
    Apr 4, 2022 at 20:12
  • Is it two bytes for the days since...?
    – Brian H
    Apr 4, 2022 at 20:54
  • 2
    @BrianH Since the infamous First of January 1980 :))
    – Raffzahn
    Apr 4, 2022 at 20:55
  • 1
    @user3840170 that’s a good point; I was thinking more along the lines of example programs in books showing how the clock interface works. (I suspected that if I said no programs used CLOCK$, someone would mention those; one can never win apparently!) Apr 5, 2022 at 5:08
  • 1
    @StephenKitt Oh, don’t worry. I might have deliberately written that, so they do, taking advantage of Cunningham’s law… Apr 5, 2022 at 6:53
5

but was there ever any software that would access the CLOCK$ device file directly, or did DOS do any operations on the file itself internally?

Hard to say for user side software, but DOS did internally query the clock driver whenever date and/or time was needed for file handling or requested by a user program.

I think there could be some internal hooks that would use whatever functions provided by a clock driver installed to the system,

No, there were no internal hooks, DOS only used the public read/write interface via the device driver. The only shortcut was what it didn't open the device via it's name, but did a lookup using a dedicated bit in the driver attribute word to find the active system clock driver. That way it could call the driver without opening it first.

but I'm more interested if there was any use for the device file directly,

So other programs could as well use the driver direct, without going thru DOS first. In addition, the CLOCK driver made a prime example to write a device driver :))


The CLOCK Device

From the MS-DOS 3.3 Programmer's Reference:

2.10  The CLOCK Device


MS-DOS assumes that some sort of clock is available in the system.
This may either be a CMOS real-time clock or an interval timer that
is initialized at boot time by the user. The CLOCK device defines and
performs functions like any other character device, except that it is
identified by a bit in the attribute word. The DOS uses this bit to
identify it; consequently, the CLOCK device may take any name. The IBM
implementation uses the name $CLOCK so as not to conflict with existing
files named clock.

The CLOCK device is unique in that MS-DOS will read or write a 6-byte
sequence that encodes the date and time. A write to this device will set
the date and time; a read will get the date and time.

Figure 2.7 illustrates the binary time format used by the CLOCK device:


    byte 0   byte 1   byte 2    byte 3   byte 4   byte 5
+--------+--------+---------+--------+--------+---------+
|        |        |         |        |        |         |
|days since 1-1-80| minutes |  hours | sec/100| seconds |
|low byte|hi byte |         |        |        |         |
+--------+--------+---------+--------+--------+---------+

            Figure 2.7  Format of a Clock Device

(Note the spelling of $CLOCK for PC-DOS)


Usage

The Clock device driver offered an interface to query or set date and time. In all respects CLOCK$ defines and performs functions like any other character device, though most functions will clear the error bit, set the done bit and return. Reading or writing is done with exactly 6 byte transferred:

DOS does not do time keeping, but reads CLOCK$ whenever date/time is needed. This includes user requests for date (INT 21h Function 2Ah) or time ($2C), but as well all (writing) file access. Similar it writes to CLOCK$ when date ($2B) or time ($2D) is set.

The default CLOCK$ driver uses the systemtick (INT 1Ah) for time keeping (*1). Drivers for clock cards do (usually) read their respective Real Time Clock (RTC), converting to above format. There are as well third party drivers doing so for AT-class machines, as the default driver does not honour the build in RTC, except for first time initialisation.


*1 - This, BTW, introduces two very specific errors. Reading the system tick via INT 1Ah Function 00h delivers a 32 bit number of clock ticks (18.2 per second) since midnight in CX:DX and a roll-over flag in AL. A non-zero value signals that a roll-over has happened. Whenever the counter reaches 1573040, it'll be reset to zero and the flag for roll-over set. The flag is reset after the first query reporting it. This introduces two subtile errors:

  • If any user program queries INT 1Ah/00h after midnight, but before the default clock driver does, then the CLOCK diver will not see it, thus not advance the date.

  • If more than a day passes between two calls (like on a PC idling over a weekend), the day is still only advanced by a single day, thus loosing one or more days.

In some DOS versions the flag was turned into a counter, recording the days passed, eliminating the second error. This explains why direct RTC reading drivers were quite welcome :))

1
  • 1
    Technically, DOS could access drivers by name without “opening” them as well. But really, even when using a direct pointer, DOS used an FCB anyway, so perhaps the devices were always open ;-). Apr 5, 2022 at 5:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .