COMAVAIL --- help to manage COM port contention, Ver. 1.00
COMAVAIL is a simple but essential utility to prevent multiple programs from
trying to use the same COM port at the same time, by managing atomic lock
files. It is NOT DESQview-specific, but is only really useful with DESQview,
DESQview/X, TopView, OmniView, DoubleDOS, or other multitaskers of that sort.
Under a multitasking environment, it is difficult and expensive to handle
multiple programs attempting to access a COM port. Windows 3.x and OS/2 2.0
deal with this by using the 386's "IOPL" mechanism to intercept hardware
accesses of the COM port --- but to compensate for the cost in speed they
must provide their own COM drivers which use buffering and other techniques.
Otherwise characters would be dropped because of the delay introduced by the
IOPL exception processing. (You can see this in OS/2 2.0: configure a DOS
window with COM_DIRECT turned ON and run a DOS comm program. OS/2 will use
a straightforward "trap the hardware access, verify it, and pass it on"
without its normal buffering and emulation, and you will see lost characters
at 9600 baud unless you have a 16550 (and a decrease in efficiency if you do
have one).) DESQview does not have this speed penalty --- or the memory
penalty of the special COM drivers, their buffers, or the 386 task
structures and their IOPL bitmaps --- but it also cannot detect or resolve
COM port contention.
The traditional solution is lock files. Use a file with a specific name
(say, C:\TMP\LCK_COM1.LCK) to indicate that the port is in use; if the file
exists, the port is busy --- otherwise create the file. Then use the port.
When you're done, delete the lock file. Unfortunately, this can't be done
in the naive way because of a "race condition". Consider the following
Task ATask B
check for lock filesuspended
(DESQview task switch)
suspendedcheck for lock file
create lock file
(DESQview task switch)
create lock filesuspended
At the end of this sequence both Task A and Task B think they have exclusive
access to the port! In effect, Task A and Task B are in a race to see which
one can get the port first --- but in this scenario *both* "win", and
therefore both lose. This is the classic "race condition" of multitasking.
If the operations "check for lock file" and "create lock file" are not a
single atomic operation (meaning that a task switch cannot occur in the
middle of the operation), the possibility exists that two processes will
both create the lock file "at the same time" without seeing each other.
In DOS 3.0 and later, a solution was provided to this problem. The "open"
call can be given the option "O_EXCL" to indicate that the file must not
exist. (Of course, this is only meaningful with the "O_CREAT" flag.) DOS
guarantees that the test and the file create will be atomic (i.e. not be
interrupted). This was intended to solve race conditions in a network
environment, but it works just as well with DESQview and other multitaskers
because they can not safely perform a task switch while a program is making
an INT 21 call.
That's all COMAVAIL does: given a port number and a command and arguments,
it attempts to creat a lock file for that port with the O_EXCL flag. If the
create fails, COMAVAIL aborts. If it succeeds, COMAVAIL runs the command,
then deletes the lock file and exits, passing on the command's exit status
for use in ERRORLEVEL statements. It's a very simple program, but if you
run multiple communications programs on a single port (as I do: I use a
comm program on my modem, and also have UUPC/Extended fire up once an hour
to collect mail from a locak Unix system) it keeps the programs from messing
with each other.
To use COMAVAIL, copy COMAVAIL.EXE to some convenient location. Edit your
comm programs' .DVP files with DESQview's "Change a Program" or DESQview/X's
DVPMAN. Let's say you put COMAVAIL.EXE in C:\DV, and your DVP looks like:
Your modem is on COM1. Change the command to read
Command: C:\DV\COMAVAIL.EXE 1 C:\TELEMATE\TM.EXE
That's it! COMAVAIL will check for the lock file before running the program,
so you won't even need to worry about TM.EXE reinitializing the serial port.
(It doesn't help with the UUPC/Extended window covering up your Telemate
window and grabbing your keystrokes while you're in the middle of replying
to a message, though. 🙂
COMAVAIL is simple and small --- you shouldn't need to adjust the memory
sizes in your DVPs unless you're *really* tight on space.
COMAVAIL accepts port numbers from 1 to 8. Note that, since COMAVAIL itself
does not access the serial ports, you can borrow "unavailable" ports for
other purposes: I use "COMAVAIL 4" to lock UUPC/Extended's "UUXQT" program,
since UUXQT doesn't check to see if it's already running and the COM4
address in my system has an 8514/A-compatible video card in it instead of a
*** There is a very minor nit in the binary provided: the "File already
exists" error message is doubled. ("comavail: can't lock: File already
existsFile already exists") This is a problem with the error message
strings in the Borland C++ 3.0 library, not with COMAVAIL. Since it doesn't
affect the program's performance in any way, I haven't tried to fix it.
I hope this helps anyone who is having COM port contention problems. As I
mentioned, there are "better" solutions that don't require editing your
.DVP's, but they cost more in terms of speed and memory; COMAVAIL is a
pretty good alternative.
Brandon S. Allbery
"Brandon Allbery" on QOS [email protected]