Hello all. I'm using OZ in a multithreaded network application where it
is imperative that no thread cause the entire oz emulator to block.
Unfortunately, as implemented, the "connect" function of the OS module
will block the entire oz-emulator, in particular if the connection
attempt is to a host that does not exist, or to a port on which there is
no service.
"connect" can be made to be non-blocking (at least in UNIX) using a
method described in the book "Unix Network Programming, Vol. 1" by W.
Richard Stevens (pp. 409-422).
However, I'm having trouble implementing this in the OZ code. I'm
certain that the osconnect() function in the file os.cc needs to be
changed to the following:
--- START CODE ---
int osconnect(int s, struct sockaddr *addr, int namelen)
{
osBlockSignals();
// MAKE 's' NON-BLOCKING
int flags = fcntl(s, F_GETFL);
fcntl(s, F_SETFL, flags | O_NDELAY);
// "connect" WILL NOT BLOCK
// "ret" WILL EITHER BE 0, INDICATING SUCCESSFUL connect,
// OR -1, WITH errno SET TO "EINPROGESS", INDICATING THAT connect
// IS NOT YET COMPLETE
int ret = connect(s,addr,namelen);
// MAKE 's' BLOCKING AGAIN (PROBABLY DOESN'T MATTER)
fcntl(s, F_SETFL, flags); // MAKE '
osUnblockSignals();
return ret;
}
---- END CODE ----
Here's where I'm stuck:
The function that calls osconnect, i.e. "unix_connectInet" in the
"unix.cc" file, needs to be changed to detect errno == EINPROGRESS, and
suspend the current thread until the file descriptor used in the connect
becomes writeable. The needed changes are outlined below:
--- START CODE ---
OZ_BI_define(unix_connectInet,3,0)
{
// ...
int ret = osconnect(s,(struct sockaddr *) &addr,sizeof(addr));
// CONNECT SUCCESSFUL
if (ret == 0) return PROCEED;
// CONNECT STILL IN PROGRESS
if (errno == EINPROGRESS) {
// SET UP "nbConnectCheck" TO BE CALLED BY OZ SCHEDULER
// WHEN 's' FILE DESCRIPTOR BECOMES WRITABLE
OZ_registerWriteHandler(s, nbConnectCheck, 0);
// HELP! NEED TO SOMEHOW SUSPEND THE CURRENT THREAD
// AND HAVE IT RESUME WHEN 's' FILE DESCRIPTOR BECOMES WRITABLE.
// ...
}
// BAD CONNECT
Assert(errno != EINTR);
RETURN_UNIX_ERROR("connect");
} OZ_BI_end
int nbConnectCheck(int s, void *) {
// HELP! NEED TO RESUME THREAD THAT WAS SUSPENDED ABOVE.
int error;
// ONCE 's' FILE DESCRIPTOR IS WRITABLE, CHECK STATUS WITH getsockopt
if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &error, sizeof(error) ) <
0 ) {
RETURN_UNIX_ERROR("connect");
} else {
return PROCEED;
}
}
---- END CODE ----
Am I even on the right track here? Can someone tell me what to do, or
point me in the right direction?
Any help would be *greatly appreciated*.
Thanks
-- Dr. Harmon S. Nine
-
Please send submissions to hackers@mozart-oz.org
and administriva mail to hackers-request@mozart-oz.org.
The Mozart Oz web site is at http://www.mozart-oz.org/.