[comp.os.msdos.programmer] far, near, and TC++1.01 objects

minar@reed.UUCP (Nelson Minar) (11/07/90)

  Summary: getting the environment (various segment registers, etc)
right for C++ class-member-functions that are called via callback or
interrupt. Exactly how is the memory reference to static members of
objects implemented in TC++ 1.01?  How does one write an assembly
program that can interface cleanly with objects of classes (name
demangling aside).

  I am trying to be clever in C++, and write a class Mouse.  The
specific model I am interested in adopting is somewhat similar to a
Macintosh: there is a mouse object who has a member function
getNextEvent().  When that function is called, the first event on the
queue (button down or button up events, specifically) is returned.  In
order to accomplish that, I am hooking the mouse driver to call a
function I specify (via INT 0x33, service 0x0c) upon mouse events
(button presses). This function should examine the mouse event the
driver has notified me of and store it on the queue.

  Currently I am working in the small model.  The problem is, when my
function 'static void far Mouse::handler()' is called by the mouse
callback mechanism, the CPU is a little confused. (Note that this call
itself is NOT a software interrupt, it is a plain old far call)  The
confusion is a result of the data segment being set to the DS of the
mouse driver, and not the DS of the object which I am trying to queue
mouse events into (I assume, other environmental aspects besides
the DS are munged, too).

  I can get around the data segment problem by being really clever,
storing the data segment of the mouse object into global far memory
(upon initialization of the Mouse object), and having my handler() load
the data segment explicitly (_DS = globalSavedDS).  Doing this gets me
pretty far: global near variables, as well as instance variables of the
class Mouse can be diddled with. (so, for example, the instance variable
Mouse::count can be incremented with success within the handler()).

  However, when I go to call my (debugged) enque() to store the event I
have caught into the queue, all hell breaks loose.  I need to use the
pointer to the queue that is stored as a member variable of my class
Mouse.  I can find it, by whacking at the data segment.  However, the
first call used off of this pointer and the stack overflow logic kicks
in and reports "Stack Overflow!" (disabling the SO checking just makes
my program crash the machine) I can't really tell how the SO logic is
supposed to work, but I dont think its the stack pointer that is
triggering the error, but rather the number in memory it is comparing it
to (which is no doubt in the wrong segment). But I can't be sure.
Regardless, this is a symptom of a larger problem.

  I've tried to be less clever. I tried just compiling the dumb thing
under the large model, with no monkeying of the data segment. I tried
converting all the pointer references to far pointer references. No
luck. I would love to declare the whole Mouse object to be far ('Mouse
far myMouse').  That's illegal, according to TC++ 1.01.  I even tried
making my handler function not actually be a member function of the
class, and to get at the data via a globally-stored 'this' pointer. This
got confusing quickly, and seemed to be the wrong answer.

  I need to know more about the internals of the machine and compiler,
even though I don't want to.  I want to be able to set up the same
ENVIRONMENT upon mouse-driver-callback that would be there if the
function were called through more normal means.  Finding the correct DS
is a long way towards the goal, but other things are wrong.

  I have considered junking the whole C++ handler function, and writing
the code in assembly.  Borland's documentation concerning assembly
interfacing to C++ code (not C code) is nonexistant.  Furthermore, the
same problem exists: how do I create that environment?

  Has anyone done something like this? I assume the problem is the same
for member functions of classes that are called within interrupts (as
opposed to callbacks, like my application), and as such, should be fairly
common in some systems programming.  The whole point of C++ is that one
should still be able to get to the bare metal if needed. This one isn't
working.

(some code, pared down)

// the actual Mouse.  Then handler() function is called asynchrously, with
// an environment that is all messed up..
class Mouse {
public:
  enum mStatus {ok, error};

  mStatus reset();                               // reset mouse driver, hook
                                                 // the mouse driver
  MouseEvent getNextEvent();

private:
  static void far handler();                     // mouse driver callback func
  static MEventQueue * eq;                       // queue of events
};


// the Queue of events.  The definiton of class Node is left out for brevity

class MEventQueue {
public:
  void enq(MouseEvent);                          // add a new data item
private:
  Node * q;
};

// drop a data item at the end of the linked list
void
MEventQueue::enq(MouseEvent d) {
  if (q == NULL) {                               // first element
    q = new Node(d);                             // all thats needed
  } else {
    Node  * p = q;
    while (p->nextNode != NULL)                  // find the end of the list
      p = p->nextNode;
    p->nextNode = new Node(d);                   // add the new node
  }
  return;
}


// the handler code itself.  This is called from anywhere in the address
// space, and God only knows what the various registers (DS, SS included)
// are going to look like.

unsigned globalDS;                               // initialized to the data
                                                 // segment storing the mouse
                                                 // object (this works)
void far
Mouse::handler() {
  unsigned tempDS = _DS;                         // diddle with the segs so the
  _DS = globalDS;                                // small model works ok

  eq->enq(MouseEvent(buttonDown, leftB, 0, 0));  // the constructor call here
                                                 // fails. So does any call of
                                                 // a function, with
                                                 // 'Stack Overflow!'

  count++;                                       // this will work, simply
                                                 // incrementing a member
                                                 // variable. Grr!

  _DS = tempDS;                                  // restore the old seg regs
}


Thank you for reading this far. Not many have, no doubt.
__
\/ minar@reed.bitnet                         You know in your heart its flat.
-- 
__
\/ minar@reed.bitnet                         You know in your heart its flat.