Newsgroups: comp.sources.unix From: voodoo@hitl.washington.edu (Geoffery Coco) Subject: v26i194: veos-2.0 - The Virtual Environment Operating Shell, V2.0, Part11/16 Sender: unix-sources-moderator@vix.com Approved: paul@vix.com Submitted-By: voodoo@hitl.washington.edu (Geoffery Coco) Posting-Number: Volume 26, Issue 194 Archive-Name: veos-2.0/part11 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'kernel_private/src/shell/xv_native.c' <<'END_OF_FILE' X/**************************************************************************************** X * * X * file: xv_native.c * X * * X * the xlisp wrappers for the VEOS native prims. * X * * X * creation: December, 1991 * X * * X * * X * by Geoffrey P. Coco at the HITLab, Seattle. * X * * X ****************************************************************************************/ X X X X/**************************************************************************************** X * Copyright (C) 1992 Geoffrey P. Coco, Human Interface Technology Lab, Seattle * X ****************************************************************************************/ X X X X/**************************************************************************************** X Preliminaries X ****************************************************************************************/ X X#include X#include "xlisp.h" X X/* VEOS definitions: */ X#include "kernel.h" X X#define DEFINE_NATIVE_GLOBS X#include "xv_native.h" X#undef DEFINE_NATIVE_GLOBS X X/****************************************************************************************/ X XTVeosErr Native_MessageToLSpace(); Xvoid Native_ShowMatchArgs(); Xvoid Native_ShowSite(); XTVeosErr Native_XCopySiteMatches(); XTVeosErr Native_XRemoveSiteMatches(); XTVeosErr Native_XInsertEltAtSite(); Xvoid Native_NextMsg(); XTVeosErr Native_DoThrow(); X X/****************************************************************************************/ X X X X/**************************************************************************************** X Veos Primitive Wrappers X ****************************************************************************************/ X X X/****************************************************************************************/ XLVAL Native_Init() X{ X LVAL pXReturn; X int iPort; X TVeosErr iErr; X X xlsave1(pXReturn); X X if (!moreargs()) X iPort = TALK_BOGUS_FD; X else X iPort = getfixnum(xlgafixnum()); X X xllastarg(); X X X /** invoke veos kernel inialization **/ X X iErr = Kernel_Init(iPort, Native_MessageToLSpace); X if (iErr == VEOS_SUCCESS) { X X X /** create a lisp based inspace for messages **/ X X s_InSpace = xlenter("VEOS_INSPACE"); X setvalue(s_InSpace, NIL); X NATIVE_INSPACE = &getvalue(s_InSpace); X X X /** create keyword symbols for nancy prims **/ X X k_TestTime = xlenter(":TEST-TIME"); /* use with copy only */ X k_Freq = xlenter(":FREQ"); /* use with copy, put or get */ X X X /** setup invariant matcher settings in global param blocks **/ X X Native_InitMatcherPBs(); X X X /** make a uid return value to signify success **/ X X X Uid2XVect(&IDENT_ADDR, &pXReturn); X } X X X xlpop(); X X X return(pXReturn); X X } /* Native_Init */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XLVAL Native_Close() X{ X if (!KERNEL_INIT) X Native_TrapErr(NATIVE_NOKERNEL, nil); X X xllastarg(); X X Kernel_Shutdown(); X X return(true); X X } /* Native_Close */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XLVAL Native_Task() X{ X#ifndef OPTIMAL X if (!KERNEL_INIT) X Native_TrapErr(NATIVE_NOKERNEL, nil); X X xllastarg(); X#endif X X /** talk will call our message handler and stuff the inspace **/ X X Kernel_SystemTask(); X X X return(true); X X } /* Native_Task */ X/****************************************************************************************/ X X X X X/****************************************************************************************/ XLVAL Native_Put() X{ X TVeosErr iErr; X TTimeStamp tNow; X X#ifndef OPTIMAL X if (!KERNEL_INIT) X Native_TrapErr(NATIVE_NOKERNEL, nil); X#endif X X X X /** get mandatory data argument **/ X X native_putPB.pXReplaceElt = xlgetarg(); X X X X /** get pattern from xlisp args **/ X X iErr = Native_GetPatternArg(&native_putPB.pPatGr, NANCY_ReplaceMatch); X if (iErr != VEOS_SUCCESS) X Native_TrapErr(iErr, nil); X X X /** get optional frequency argument **/ X X NATIVE_FREQ_ARG(native_putPB.iFreqFlag); X X X /** set the data time-stamp **/ X X GET_TIME(tNow); X native_putPB.pStampTime = &tNow; X X X /** dispatch the matcher **/ X X xlsave1(native_putPB.pXResult); X X Native_XMandR(&native_putPB); X X xlpop(); X X X X /** clean up **/ X X Nancy_DisposeGrouple(native_putPB.pPatGr); X X X X return (native_putPB.pXResult); X X } /* Native_Put */ X/****************************************************************************************/ X X X/****************************************************************************************/ XLVAL Native_Get() X{ X TVeosErr iErr; X X#ifndef OPTIMAL X if (!KERNEL_INIT) X Native_TrapErr(NATIVE_NOKERNEL, nil); X#endif X X /** get pattern from xlisp args **/ X X iErr = Native_GetPatternArg(&native_getPB.pPatGr, NANCY_RemoveMatch); X if (iErr != VEOS_SUCCESS) X Native_TrapErr(iErr, nil); X X X /** get optional frequency argument **/ X X NATIVE_FREQ_ARG(native_getPB.iFreqFlag); X X X /** dispatch the matcher **/ X X xlsave1(native_getPB.pXResult); X X Native_XMandR(&native_getPB); X X xlpop(); X X X /** clean up **/ X X Nancy_DisposeGrouple(native_getPB.pPatGr); X X X X return (native_getPB.pXResult); X X } /* Native_Get */ X/****************************************************************************************/ X X X/****************************************************************************************/ XLVAL Native_Copy() X{ X TVeosErr iErr; X TTimeStamp tTest; X X#ifndef OPTIMAL X if (!KERNEL_INIT) X Native_TrapErr(NATIVE_NOKERNEL, nil); X#endif X X X X /** get pattern from xlisp args **/ X X iErr = Native_GetPatternArg(&native_copyPB.pPatGr, NANCY_CopyMatch); X if (iErr != VEOS_SUCCESS) X Native_TrapErr(iErr, nil); X X X /** look for optional time-stamp-test **/ X X NATIVE_TIME_ARG(native_copyPB.pTestTime, tTest); X X X /** get optional frequency argument **/ X X NATIVE_FREQ_ARG(native_copyPB.iFreqFlag); X X X /** dispatch the matcher **/ X X xlsave1(native_copyPB.pXResult); X X Native_XMandR(&native_copyPB); X X xlpop(); X X X /** clean up **/ X X Nancy_DisposeGrouple(native_copyPB.pPatGr); X X X X return (native_copyPB.pXResult); X X } /* Native_Copy */ X/****************************************************************************************/ X X X/****************************************************************************************/ XLVAL Native_Throw() X{ X LVAL pXData, pXDests; X TVeosErr iErr; X X#ifndef OPTIMAL X if (!KERNEL_INIT) X Native_TrapErr(NATIVE_NOKERNEL, nil); X#endif X X /** get dests argument **/ X X pXDests = xlgalist(); X X X /** get data argument **/ X X pXData = xlgetarg(); X X#ifndef OPTIMAL X xllastarg(); X#endif X X iErr = Native_DoThrow(pXDests, pXData); X X return(iErr == VEOS_SUCCESS ? true : NIL); X X } /* Native_Throw */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XLVAL Native_Catch() X{ X LVAL pSave; X TPElt pElt; X X#ifndef OPTIMAL X if (!KERNEL_INIT) X Native_TrapErr(NATIVE_NOKERNEL, nil); X X xllastarg(); X#endif X X Native_NextMsg(&pSave); X X return (pSave); X X } /* Native_Catch */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XLVAL Native_MinTime() X{ X TF2L fTrans; X X /* guaranteed to be earlier than any system time */ X X fTrans.u.l = NANCY_MINTIME; X X return(cvflonum(fTrans.u.f)); X X } /* Native_MinTime */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XLVAL Native_NoSignals() X{ X SIG_ENABLE = FALSE; X X return(true); X X } /* Native_NoSignals */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XLVAL Native_Bugs() X{ X LVAL pXModule; X char *sName; X X pXModule = xlgastring(); X sName = (char *) getstring(pXModule); X X if (strcmp(sName, "talk") == 0) X TALK_BUGS = TALK_BUGS ? FALSE : TRUE; X X else if (strcmp(sName, "nancy") == 0) X NANCY_BUGS = NANCY_BUGS ? FALSE : TRUE; X X else if (strcmp(sName, "shell") == 0) X SHELL_BUGS = SHELL_BUGS ? FALSE : TRUE; X X return(true); X X } /* Native_Bugs */ X/****************************************************************************************/ X Xextern int iEvals; X X/****************************************************************************************/ XLVAL Native_Zoot() X{ X static int iAlreadySeen = 0; X int iSinceLast; X X iSinceLast = iEvals - iAlreadySeen; X iAlreadySeen = iEvals; X X return(cvfixnum(iSinceLast)); X X } /* Native_Zoot */ X/****************************************************************************************/ X X X X X/**************************************************************************************** X The Beuractratic Linkage Between Veos and XLISP X ****************************************************************************************/ X X X/****************************************************************************************/ XTVeosErr Shell_LoadNativePrims() X{ X#define VEOS_NATIVE_LOAD X#include "xv_native_prims.h" X#undef VEOS_NATIVE_LOAD X X return(VEOS_SUCCESS); X } X/****************************************************************************************/ X X X/****************************************************************************************/ XTVeosErr Shell_BailOut(sErr) X char *sErr; X{ X X xlfatal(sErr); X X /** not reached **/ X X return(VEOS_SUCCESS); X X } /* Shell_BailOut */ X/****************************************************************************************/ X X X X/**************************************************************************************** X The Sticky Goo Just Beneath the Wrappers X ****************************************************************************************/ X X X/****************************************************************************************/ XTVeosErr Native_InitMatcherPBs() X{ X /** vget settings **/ X X native_getPB.pSrcGr = WORK_SPACE; X native_getPB.iDestroyFlag = NANCY_RemoveMatch; X native_getPB.pXReplaceElt = nil; X native_getPB.pStampTime = nil; X native_getPB.pTestTime = nil; X X /** vcopy settings **/ X X native_copyPB.pSrcGr = WORK_SPACE; X native_copyPB.iDestroyFlag = NANCY_CopyMatch; X native_copyPB.pXReplaceElt = nil; X native_copyPB.pStampTime = nil; X X /** vput settings **/ X X native_putPB.pSrcGr = WORK_SPACE; X native_putPB.iDestroyFlag = NANCY_ReplaceMatch; X native_putPB.pTestTime = nil; X X X return(VEOS_SUCCESS); X X } /* Native_InitMatcherPBs */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_DoThrow(pXDests, pXData) X LVAL pXData, pXDests; X{ X TPUidNode pDests; X TVeosErr iErr; X TMsgRec msgOut; X X X /** convert host/port vectors to talk uids **/ X X iErr = Native_XVectsToUids(pXDests, &pDests); X if (iErr != VEOS_SUCCESS) { X Native_TrapErr(iErr, pXDests); X } X X /** convert data element to flat network format **/ X X iErr = Native_XEltToMsgRec(pXData, &msgOut); X if (iErr != VEOS_SUCCESS) { X Native_DisposeUids(pDests); X Native_TrapErr(iErr, pXData); X } X X /** pass the flat message to veos kernel **/ X X iErr = Talk_SpeakToMany(pDests, &msgOut); X X X Native_DisposeUids(pDests); X X return(iErr); X X } /* Native_DoThrow */ X/****************************************************************************************/ X X X X/****************************************************************************************/ Xvoid Native_NextMsg(hMsg) X LVAL *hMsg; X{ X *hMsg = NIL; X X if (!null(*NATIVE_INSPACE)) { X X /** get the oldest message **/ X X *hMsg = car(*NATIVE_INSPACE); X X /** remove this msg from list immediately. X ** first cons cell in this list will thus be garbage collected. X ** pass back the new msg. X **/ X X *NATIVE_INSPACE = cdr(*NATIVE_INSPACE); X } X } X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_XMandR(pMandRPB) X TPXMandRRec pMandRPB; X{ X TVeosErr iErr; X TMatchRec matchSpec; X TPReplaceRec pSite, pSave; X X X /** Initialize the match record. X ** This record get passed through the entire match process. X ** The matcher uses to record sites for removal and insertion. X ** If the matcher returns success, X ** we then perform any destructive operations on the gspace. X **/ X X matchSpec.pPatGr = pMandRPB->pPatGr; X matchSpec.pSrcGr = pMandRPB->pSrcGr; X matchSpec.iDestroyFlag = pMandRPB->iDestroyFlag; X matchSpec.iFreqFlag = pMandRPB->iFreqFlag; X matchSpec.pReplaceList = nil; X matchSpec.pTouchList = nil; X X#ifndef OPTIMAL X if (NANCY_BUGS) X Native_ShowMatchArgs(pMandRPB); X#endif X X /************************************/ X X iErr = Nancy_MatchGrouple(&matchSpec); X X /************************************/ X X#ifndef OPTIMAL X if (NANCY_BUGS) X fprintf(stderr, "nancy %s: match %s.\n", X WHOAMI, iErr == VEOS_SUCCESS ? "succeeded" : "failed"); X#endif X X /** Perform any destructive operations on the gspace. X ** These occur in on a per-site basis. X ** A site is: X ** an enclosing grouple, X ** a set of element intervals, X ** an element index at which to insert. X ** Sites are generated by the matcher during matching. X **/ X X /** perform destructive element retrieval X **/ X X switch (pMandRPB->iDestroyFlag) { X X case NANCY_CopyMatch: X for (pSite = matchSpec.pReplaceList; X pSite && iErr == VEOS_SUCCESS; X pSite = pSite->pNext) { X#ifndef OPTIMAL X if (NANCY_BUGS) X Native_ShowSite(pSite); X#endif X iErr = Native_XCopySiteMatches(pSite, pMandRPB->pTestTime, X &pMandRPB->pXResult); X } X break; X X case NANCY_RemoveMatch: X for (pSite = matchSpec.pReplaceList; X pSite && iErr == VEOS_SUCCESS; X pSite = pSite->pNext) { X X#ifndef OPTIMAL X if (NANCY_BUGS) X Native_ShowSite(pSite); X#endif X iErr = Native_XRemoveSiteMatches(pSite, pMandRPB->pTestTime, X &pMandRPB->pXResult); X } X break; X X case NANCY_ReplaceMatch: X for (pSite = matchSpec.pReplaceList; X pSite && iErr == VEOS_SUCCESS; X pSite = pSite->pNext) { X X#ifndef OPTIMAL X if (NANCY_BUGS) X Native_ShowSite(pSite); X#endif X iErr = Native_XRemoveSiteMatches(pSite, pMandRPB->pTestTime, X &pMandRPB->pXResult); X if (iErr == VEOS_SUCCESS) X iErr = Native_XInsertEltAtSite(pMandRPB->pXReplaceElt, X pMandRPB->pStampTime, pSite); X } X break; X X case NANCY_GimmeMatch: X iErr = NANCY_NotSupported; X break; X X } /* switch */ X X X /** perform destructive element time stamping X **/ X X if (pMandRPB->pStampTime) { X X for (pSite = matchSpec.pTouchList; X pSite && iErr == VEOS_SUCCESS; X pSite = pSite->pNext) { X#ifndef OPTIMAL X if (NANCY_BUGS) X Native_ShowSite(pSite); X#endif X Native_TouchSiteMatches(pSite, *pMandRPB->pStampTime); X X } X } X X /** free all matcher memory (stays within veos kernel) **/ X X pSite = matchSpec.pReplaceList; X while (pSite) { X pSave = pSite; X pSite = pSite->pNext; X Shell_ReturnBlock(pSave, sizeof(TReplaceRec), "replace-bp"); X } X X pSite = matchSpec.pTouchList; X while (pSite) { X pSave = pSite; X pSite = pSite->pNext; X Shell_ReturnBlock(pSave, sizeof(TReplaceRec), "replace-bp"); X } X X X if (iErr == VEOS_SUCCESS) { X X /** check for successful insert (give caller appropriate feeback) **/ X X if (pMandRPB->iDestroyFlag == NANCY_ReplaceMatch && X pMandRPB->pXResult == NIL) X X pMandRPB->pXResult = true; X } X X#ifndef OPTIMAL X else { X if (NANCY_BUGS) X Nancy_TrapErr(iErr); X } X#endif X X return(iErr); X X } /* Native_MatchAndReplace */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_XCopySiteMatches(pSite, pTestTime, hXResult) X TPReplaceRec pSite; X TPTimeStamp pTestTime; X LVAL *hXResult; X{ X int iZone, iToKill, iElt, iLeft, iRight; X LVAL pXElt; X TPElt pVElt; X TVeosErr iErr; X X xlsave1(pXElt); X X /** convert outgoing data into supplanted language format. X ** lisp is the current control language X **/ X X if (pTestTime == nil) { X X for (iZone = pSite->iZones - 1; iZone >= 0; iZone --) { X iLeft = pSite->pWipeList[iZone].iLeft; X iRight = pSite->pWipeList[iZone].iRight; X iToKill = iRight - iLeft + 1; X X#ifndef OPTIMAL X if (NANCY_BUGS) { X fprintf(stderr, "nancy %s: left: %d right: %d\n", X WHOAMI, iLeft, iRight); X } X#endif X for (iElt = iRight, pVElt = &pSite->pEnviron->pEltList[iRight]; X iElt >= iLeft; X iElt--, pVElt --) { X X if (Native_VEltToXElt(pVElt, &pXElt) == VEOS_SUCCESS) X X /** assume caller protected *hXResult **/ X *hXResult = cons(pXElt, *hXResult); X } X } X } X else { X X for (iZone = pSite->iZones - 1; iZone >= 0; iZone --) { X iLeft = pSite->pWipeList[iZone].iLeft; X iRight = pSite->pWipeList[iZone].iRight; X iToKill = iRight - iLeft + 1; X X#ifndef OPTIMAL X if (NANCY_BUGS) { X fprintf(stderr, "nancy %s: left: %d right: %d\n", X WHOAMI, iLeft, iRight); X } X#endif X X for (iElt = iRight, pVElt = &pSite->pEnviron->pEltList[iRight]; X iElt >= iLeft; X iElt--, pVElt--) { X X iErr = Native_NewVEltToXElt(pVElt, &pXElt, *pTestTime); X if (iErr == VEOS_SUCCESS) { X X /** assume caller protected *hXResult **/ X *hXResult = cons(pXElt, *hXResult); X } X /* X else if (iErr == NATIVE_STALE) X iErr = VEOS_SUCCESS; X */ X } X } X } X X xlpop(); X X return(VEOS_SUCCESS); X X } /* Native_XCopySiteMatches */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_XRemoveSiteMatches(pSite, pTestTime, hXResult) X TPReplaceRec pSite; X TPTimeStamp pTestTime; X LVAL *hXResult; X{ X int iZone, iToKill, iElt, iLeft, iRight; X LVAL pXElt; X TPElt pVElt; X X xlsave1(pXElt); X X for (iZone = pSite->iZones - 1; iZone >= 0; iZone --) { X iLeft = pSite->pWipeList[iZone].iLeft; X iRight = pSite->pWipeList[iZone].iRight; X iToKill = iRight - iLeft + 1; X X /** convert outgoing data into supplanted language format. X ** that format is xlisp, and in reverse order X **/ X X for (iElt = iRight, pVElt = &pSite->pEnviron->pEltList[iRight]; X iElt >= iLeft; X iElt--, pVElt--) { X X if (Native_VEltToXElt(pVElt, &pXElt) == VEOS_SUCCESS) X X /** assume caller has protected *hXResult **/ X X *hXResult = cons(pXElt, *hXResult); X } X X Nancy_DeleteElementsInGrouple(pSite->pEnviron, X iLeft, X iToKill); X } X X xlpop(); X X return(VEOS_SUCCESS); X X } /* Native_XRemoveSiteMatches */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_XInsertEltAtSite(pXReplaceElt, pStampTime, pSite) X LVAL pXReplaceElt; X TPTimeStamp pStampTime; X TPReplaceRec pSite; X{ X TElt localElt; X TVeosErr iErr = VEOS_SUCCESS; X X if (pSite->iInsertElt >= 0) { X X localElt = NIL_ELT; X X if (pStampTime) X iErr = Native_XEltToNewVElt(pXReplaceElt, &localElt, *pStampTime); X else X iErr = Native_XEltToVElt(pXReplaceElt, &localElt); X X if (iErr == VEOS_SUCCESS) { X X Nancy_NewElementsInGrouple(pSite->pEnviron, pSite->iInsertElt, 1, X GR_unspecified, 0); X pSite->pEnviron->pEltList[pSite->iInsertElt] = localElt; X } X } X X return(iErr); X X } /* Native_XInsertEltAtSite */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_TouchSiteMatches(pSite, time) X TPReplaceRec pSite; X TTimeStamp time; X{ X int iZone, iElt, iLeft, iRight; X TPElt pVElt; X X for (iZone = pSite->iZones - 1; iZone >= 0; iZone --) { X X iLeft = pSite->pWipeList[iZone].iLeft; X iRight = pSite->pWipeList[iZone].iRight; X X /** simply update time stamp of given elements **/ X X for (iElt = iRight, pVElt = &pSite->pEnviron->pEltList[iRight]; X iElt >= iLeft; X iElt--, pVElt--) X X pVElt->tLastMod = time; X } X X return(VEOS_SUCCESS); X X } /* Native_TouchSiteMatches */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Native_MessageToLSpace(pMsgRec) X TPMsgRec pMsgRec; X{ X TVeosErr iErr; X LVAL pXElt, *hFinger; X int iLen; X char *pBuf; X X X xlsave1(pXElt); X X /** return data to grouple form **/ X X pBuf = pMsgRec->sMessage; X iLen = 0; X iErr = Native_MessageToXElt(pBuf, &pXElt, &iLen); X X#ifndef OPTIMAL X if (TALK_BUGS) { X fprintf(stderr, "listen %s: results of message conversion, native: %d\n", X WHOAMI, iErr); X } X#endif X X if (iErr == VEOS_SUCCESS) { X X#ifndef OPTIMAL X if (TALK_BUGS) { X fprintf(stderr, "listen %s: element in message:\n", WHOAMI); X X errprint(pXElt); X } X#endif X X /** append message to native inspace list **/ X X hFinger = NATIVE_INSPACE; X while (!null(*hFinger)) X hFinger = &cdr(*hFinger); X X *hFinger = cons(pXElt, NIL); X } X X xlpop(); X X return(iErr); X X } /* Native_MessageToLSpace */ X/****************************************************************************************/ X X X X/****************************************************************************************/ Xvoid Native_ShowMatchArgs(pMandRPB) X TPXMandRRec pMandRPB; X{ X fprintf(stderr, "nancy %s: MandR arguments.\n", WHOAMI); X X fprintf(stderr, "nancy %s: source:\n", WHOAMI); X Nancy_GroupleToStream(pMandRPB->pSrcGr, stderr); X X fprintf(stderr, "nancy %s: pattern:\n", WHOAMI); X Nancy_GroupleToStream(pMandRPB->pPatGr, stderr); X X fprintf(stderr, "nancy %s: destroyFlag: %s\n", WHOAMI, X pMandRPB->iDestroyFlag == NANCY_RemoveMatch ? "remove" : X pMandRPB->iDestroyFlag == NANCY_CopyMatch ? "copy" : X pMandRPB->iDestroyFlag == NANCY_ReplaceMatch ? "replace" : "unknown"); X X fprintf(stderr, "nancy %s: freqFlag: %s\n", WHOAMI, X pMandRPB->iFreqFlag == NANCY_MatchOne ? "one" : "all"); X X fprintf(stderr, "nancy %s: replace elt:\n", WHOAMI); X errprint(pMandRPB->pXReplaceElt); X X fprintf(stderr, "nancy %s: stamp-time: ", WHOAMI); X if (pMandRPB->pStampTime) X PRINT_TIME(*pMandRPB->pStampTime, stderr); X else X fprintf(stderr, "nil"); X fprintf(stderr, "\n"); X X fprintf(stderr, "nancy %s: test-time: ", WHOAMI); X if (pMandRPB->pTestTime) X PRINT_TIME(*pMandRPB->pTestTime, stderr); X else X fprintf(stderr, "nil"); X fprintf(stderr, "\n"); X X } X/****************************************************************************************/ X X X X/****************************************************************************************/ Xvoid Native_ShowSite(pSite) X TPReplaceRec pSite; X{ X fprintf(stderr, "nancy %s: site grouple:\n", WHOAMI); X Nancy_GroupleToStream(pSite->pEnviron, stderr); X fprintf(stderr, "nancy %s: site zones: %d\n", WHOAMI, pSite->iZones); X fprintf(stderr, "nancy %s: site insert elt: %d\n", WHOAMI, pSite->iInsertElt); X } X/****************************************************************************************/ X X X END_OF_FILE if test 24300 -ne `wc -c <'kernel_private/src/shell/xv_native.c'`; then echo shar: \"'kernel_private/src/shell/xv_native.c'\" unpacked with wrong size! fi # end of 'kernel_private/src/shell/xv_native.c' fi if test -f 'kernel_private/src/talk/talk.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'kernel_private/src/talk/talk.c'\" else echo shar: Extracting \"'kernel_private/src/talk/talk.c'\" \(24919 characters\) sed "s/^X//" >'kernel_private/src/talk/talk.c' <<'END_OF_FILE' X/**************************************************************************************** X * * X * file: talk.c * X * * X * October 20, 1990: an entity's network interface to other entities. * X * * X * this library represents the presentation & session layers of the * X * ISO network systems model. * X * * X * the network and transport layers provided by socket.c * X * * X * by Geoffrey P. Coco at the HITLab, Seattle. * X * * X ****************************************************************************************/ X X X/**************************************************************************************** X * Copyright (C) 1992 Geoffrey P. Coco, Human Interface Technology Lab, Seattle * X ****************************************************************************************/ X X X/**************************************************************************************** X Preliminaries X ****************************************************************************************/ X X#include "kernel.h" X#include "errno.h" X#include "sys/signal.h" X X/****************************************************************************************/ X XTVeosErr Talk_DummyMsgHandler(); X X/****************************************************************************************/ X X X X/**************************************************************************************** X * Talk_HelloTalk * X * * X * talk initialization. call Talk_HelloTalk() once, and don't proceed upon failure. */ X XTVeosErr Talk_HelloTalk(iPort, pMessFun) X int iPort; X TVeosErr (*pMessFun) (); X{ X TVeosErr iErr; X X X /** allocate fast message buffers **/ X X iErr = VEOS_MEM_ERR; X if (NEWPTR(TALK_BUFFER, char *, TALK_MAX_BUFFER)) { X X X /** initialize cache settings **/ X X SPEAK_SET = nil; X X LISTEN_SOCKETFD = TALK_BOGUS_FD; X LISTEN_SET = nil; X X FD_ZERO(&OPEN_READ_SOCKETS); X FD_ZERO(&OPEN_WRITE_SOCKETS); X X TALK_MSG_FUNC = pMessFun ? pMessFun : Talk_DummyMsgHandler; X X bzero(SOCK_HOSTS, 26 * sizeof(TPHostNode)); X X X /** initialize public cache settings **/ X X SPEAK_DIRTY = FALSE; X X X X /** initialize listen connection **/ X X iErr = Talk_OpenPort(iPort); X } X X return(iErr); X X } /* Talk_HelloTalk */ X/****************************************************************************************/ X X X X X/**************************************************************************************** X * Talk_ByeTalk * X * * X * cleanup network and memory allocation only after finished using talk library. */ X XTVeosErr Talk_ByeTalk() X{ X TPSpeakNode pSpeakFinger, pTempSpeak; X TPListenNode pListenFinger, pTempListen; X X /** take down listen port **/ X X Talk_ClosePort(); X X X /** close all speak connections **/ X X pSpeakFinger = SPEAK_SET; X while (pSpeakFinger) { X X pTempSpeak = pSpeakFinger->pLink; X X Talk_KillSpeakConnection(pSpeakFinger); X X pSpeakFinger = pTempSpeak; X } X X X /** close listen connections (normal mechanism is while attempting to read) **/ X X pListenFinger = LISTEN_SET; X while (pListenFinger) { X X pTempListen = pListenFinger->pLink; X X Talk_KillListenConnection(pListenFinger); X X pListenFinger = pTempListen; X } X X X /** deallocate local library cache **/ X X if (TALK_BUFFER) X DUMP(TALK_BUFFER); X X X return(VEOS_SUCCESS); X X } /* Talk_ByeTalk */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Talk_SpeakToMany(pDests, pMsg) X TPUidNode pDests; X TPMsgRec pMsg; X{ X TVeosErr iErr; X TPUidNode pFinger; X X iErr = VEOS_FAILURE; X X if (pDests && pMsg) { X X iErr = VEOS_SUCCESS; X X pFinger = pDests; X while (pFinger && iErr == VEOS_SUCCESS) { X X iErr = Talk_PostSpeakMessage(&pFinger->addr, pMsg); X X pFinger = pFinger->pNext; X } X } X X return(iErr); X X } /* Talk_SpeakToMany */ X/****************************************************************************************/ X X X X/**************************************************************************************** X * private functions * X ****************************************************************************************/ X X X/**************************************************************************************** X * Talk_OpenPort * X * * X * establish an incoming message gateway for the entity client. * X * Talk_OpenPort() should be paired with a call to Talk_ClosePort(). */ X XTVeosErr Talk_OpenPort(iPort) X int iPort; X{ X TVeosErr iErr; X boolean bFound; X X X /** install entity connection handler **/ X/* X signal(SIGIO, Talk_ConnectTrap); X*/ X X X /** initiate network comminication. alert world of our existence. **/ X X if (TALK_BUGS) X fprintf(stderr, "listen %s: trying to listen...\n", WHOAMI); X X X if (iPort != TALK_BOGUS_PORT) { X X /** use chosen port number **/ X X iErr = Sock_Listen(&LISTEN_SOCKETFD, X iPort, X "tcp", X TALK_AGRESSIVE); X } X else { X /** try all sockets until we find an unused one **/ X X iPort = TALK_MIN_PORT; X iErr = VEOS_FAILURE; X X while (iErr != VEOS_SUCCESS && X iPort < TALK_MAX_PORT) { X X iErr = Sock_Listen(&LISTEN_SOCKETFD, X iPort, X "tcp", X TALK_PASSIVE); X if (iErr != VEOS_SUCCESS) X iPort ++; X } X } X X X if (iErr != VEOS_SUCCESS) { X if (TALK_BUGS) X fprintf(stderr, "listen %s: cannot listen, talk: %d, sys: %d\n", X WHOAMI, iErr, errno); X } X X else { X /** maintain references to entity uid **/ X X IDENT_ADDR.iPort = iPort; X Shell_UpdateUid(); X X if (TALK_BUGS) X fprintf(stderr, "listen %s: successful listen\n", WHOAMI); X X X /** setup shared memory channel **/ X X iErr = ShMem_Init(); X } X X return(iErr); X X } /* Talk_OpenPort */ X/****************************************************************************************/ X X X X/**************************************************************************************** X * Talk_ClosePort * X * * X * close the incoming message gateway. the cleanup counterpart to Talk_OpenTalk(). */ X XTVeosErr Talk_ClosePort() X{ X TVeosErr iErr; X X X /** unregister ourselves from net **/ X X if (TALK_BUGS) X fprintf(stderr, "listen %s: about to close main listen socket: %d, sys: %d\n", X WHOAMI, LISTEN_SOCKETFD, errno); X X X iErr = Sock_Close(&LISTEN_SOCKETFD); X X if (TALK_BUGS) X fprintf(stderr, "listen %s: closed main listen port, talk: %d, sys: %d\n", X WHOAMI, iErr, errno); X X X /** takedown shared memory channel **/ X X ShMem_Close(); X X X return(iErr); X X } /* Talk_ClosePort */ X/****************************************************************************************/ X X X X X/****************************************************************************************/ XTVeosErr Talk_GatherListenMessages() X{ X TVeosErr iErr; X int iSocketFD; X THListenNode hListenFinger; X TPListenNode pSaveLink; X X X hListenFinger = &LISTEN_SET; X X while (*hListenFinger) { X X pSaveLink = *hListenFinger; X iSocketFD = (*hListenFinger)->iSocketFD; X X X /** attempt to read messages from the connection **/ X X iErr = Talk_RetrieveMessages(iSocketFD); X if (iErr != TALK_CONN_CLOSED) X X hListenFinger = &(*hListenFinger)->pLink; X X X else { X /** connection was lost from other end **/ X X if (TALK_BUGS) X fprintf(stderr, "listen %s: lost connection on socket: %d\n", X WHOAMI, iSocketFD); X X pSaveLink = (*hListenFinger)->pLink; X X Talk_KillListenConnection(*hListenFinger); X X *hListenFinger = pSaveLink; X } X } X X X /** all shared memory messages come in through one channel **/ X X ShMem_GatherMessages(); X X X return(iErr); X X } /* Talk_GatherListenMessages */ X/****************************************************************************************/ X X X X X/**************************************************************************************** X * Talk_EstNewListenConnections */ X XTVeosErr Talk_EstNewListenConnections() X{ X TVeosErr iErr = VEOS_SUCCESS; X TPListenNode pNewNode; X X iErr = Talk_NewListenConnection(LISTEN_SOCKETFD, &pNewNode); X if (iErr == VEOS_SUCCESS) { X X /** store this record locally **/ X X pNewNode->pLink = LISTEN_SET; X LISTEN_SET = pNewNode; X } X X return(VEOS_SUCCESS); X X } /* Talk_EstNewListenConnections */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Talk_DispatchQedSpeakMessages() X{ X TVeosErr iErr; X THSpeakNode hSpeakFinger; X TPSpeakNode pSaveLink; X boolean bLocalDirty; X X iErr = VEOS_SUCCESS; X X X /** inspect every open connection for queued outgoing messages **/ X X hSpeakFinger = &SPEAK_SET; X SPEAK_DIRTY = FALSE; X X while (*hSpeakFinger) { X X X /** attempt to send queued messages for this connection in order **/ X X iErr = Talk_ThrowMessages(*hSpeakFinger, &bLocalDirty); X if (iErr == TALK_CONN_CLOSED) { X X X /** connection was lost from other end **/ X X if (TALK_BUGS) X fprintf(stderr, "speak %s: lost connection to (%d %d) on socket: %d\n", X WHOAMI, X (*hSpeakFinger)->destRec.lHost, X (*hSpeakFinger)->destRec.iPort, X (*hSpeakFinger)->iSocketFD); X X pSaveLink = (*hSpeakFinger)->pLink; X X Talk_KillSpeakConnection(*hSpeakFinger); X X *hSpeakFinger = pSaveLink; X } X X else { X if (bLocalDirty) X SPEAK_DIRTY = TRUE; X X X /** check next connection **/ X X hSpeakFinger = &(*hSpeakFinger)->pLink; X } X } X X return(iErr); X X } /* Talk_DispatchQedSpeakMessages */ X/****************************************************************************************/ X X X X X/**************************************************************************************** X * Talk_NewListenConnection */ X XTVeosErr Talk_NewListenConnection(iListenSocketFD, hListenNode) X int iListenSocketFD; X THListenNode hListenNode; X{ X TPListenNode pNewNode; X TVeosErr iErr; X int iSocketFD; X X X iErr = Sock_ReadSelect(iListenSocketFD); X if (iErr == VEOS_SUCCESS) { X X if (TALK_BUGS) X fprintf(stderr, "listen %s: another entity is trying to connect...\n", X WHOAMI); X X /** establish a full-duplex connection **/ X X iErr = Sock_Accept(iListenSocketFD, &iSocketFD); X X if (iErr != VEOS_SUCCESS) X perror("talk: _Accept"); X X else { X X if (TALK_BUGS) X fprintf(stderr, "listen %s: another entity connected on socket: %d\n", X WHOAMI, iSocketFD); X X /** allocate listen connection record **/ X X iErr = Shell_NewBlock(sizeof(TListenNode), &pNewNode, "listen node"); X if (iErr != VEOS_SUCCESS) { X X Sock_Close(&iSocketFD); X } X X else { X /** setup connection record **/ X X pNewNode->iSocketFD = iSocketFD; X pNewNode->pLink = nil; X X *hListenNode = pNewNode; X } X } X } X X return(iErr); X X } /* Talk_NewListenConnection */ X/****************************************************************************************/ X X X X X/****************************************************************************************/ XTVeosErr Talk_KillListenConnection(pDeadNode) X TPListenNode pDeadNode; X{ X TVeosErr iErr; X X iErr = VEOS_FAILURE; X X if (pDeadNode) { /* sane? */ X X if (TALK_BUGS) X fprintf(stderr, "listen %s: closing connection on socket: %d\n", X WHOAMI, pDeadNode->iSocketFD); X X /** strike this connection in all respects **/ X X iErr = Sock_Close(&pDeadNode->iSocketFD); X X X if (TALK_BUGS) X fprintf(stderr, "listen %s: closed listen connection, talk: %d, sys: %d\n", X WHOAMI, iErr, errno); X X X Shell_ReturnBlock(pDeadNode, sizeof(TListenNode), "listen node"); X X iErr = VEOS_SUCCESS; X } X X return(iErr); X X } /* Talk_KillListenConnection */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Talk_PostSpeakMessage(pDest, pMsgBlock) X TPUid pDest; X TPMsgRec pMsgBlock; X{ X TVeosErr iErr; X TPSpeakNode pDestNode, pSaveLink; X THSpeakNode hFinger; X boolean bLocalDirty; X X if (pDest) { X X X /** do we already have a connection to this destination? **/ X X hFinger = &SPEAK_SET; X iErr = VEOS_FAILURE; X X while (*hFinger && iErr != VEOS_SUCCESS) { X X if (UID_COMPARE(&(*hFinger)->destRec, pDest)) { X X pDestNode = *hFinger; X iErr = VEOS_SUCCESS; X } X else X hFinger = &(*hFinger)->pLink; X } X X X /** attempt to connect to this destaination for the first time **/ X X if (iErr != VEOS_SUCCESS) { X iErr = Talk_NewSpeakConnection(pDest, X &pDestNode); X if (iErr == VEOS_SUCCESS) { X X /** add connection record to local list **/ X X pDestNode->pLink = SPEAK_SET; X SPEAK_SET = pDestNode; X hFinger = &SPEAK_SET; X } X } X X X /** add new message to this connection's queue **/ X X if (iErr == VEOS_SUCCESS) { X iErr = Talk_AddSpeakJob(pDestNode, pMsgBlock); X if (iErr == VEOS_SUCCESS) { X X X /** attempt to send this message right now **/ X X iErr = Talk_ThrowMessages(pDestNode, &bLocalDirty); X if (iErr == TALK_CONN_CLOSED) { X X X /** connection was lost from other end **/ X X if (TALK_BUGS) X fprintf(stderr, "speak %s: lost connection to (%d %d) on socket: %d\n", X WHOAMI, X pDestNode->destRec.lHost, X pDestNode->destRec.iPort, X pDestNode->iSocketFD); X X X pSaveLink = pDestNode->pLink; X X Talk_KillSpeakConnection(pDestNode); X X *hFinger = pSaveLink; X } X X else if (bLocalDirty) X SPEAK_DIRTY = TRUE; X } X } X } X X return(iErr); X X } /* Talk_PostSpeakMessage */ X/****************************************************************************************/ X X X X/**************************************************************************************** X * Talk_NewSpeakConnection */ X XTVeosErr Talk_NewSpeakConnection(pDest, hSpeakNode) X TPUid pDest; X THSpeakNode hSpeakNode; X{ X TPSpeakNode pNewNode; X int iSocketFD; X TPSharedRec pChannel; X TVeosErr iErr; X boolean bSharedMem; X X *hSpeakNode = nil; X X X /** try to connect to destination shell **/ X X if (TALK_BUGS) X fprintf(stderr, "speak %s: trying to connect to entity: (%d %d)\n", X WHOAMI, pDest->lHost, pDest->iPort); X X X /** special case communications - shared memory **/ X X bSharedMem = ShMem_CanShareMem(pDest); X X if (bSharedMem) { X iErr = ShMem_FindChannel(pDest->iPort, &pChannel); X } X else { X iErr = Sock_Connect(&iSocketFD, X pDest, X TALK_DEFAULT_PROTOCOL); X } X X X if (iErr != VEOS_SUCCESS) { X X if (TALK_BUGS) X fprintf(stderr, "speak %s: cannot connect, talk: %d, sys: %d\n", X WHOAMI, iErr, errno); X X iErr = VEOS_FAILURE; X } X X else { X X if (TALK_BUGS) X fprintf(stderr, "speak %s: connected to entity: (%d %d) on socket: %d\n", X WHOAMI, pDest->lHost, pDest->iPort, iSocketFD); X X X /** allocate a new connection record **/ X X iErr = Shell_NewBlock(sizeof(TSpeakNode), &pNewNode, "speak node"); X if (iErr != VEOS_SUCCESS) { X X if (!bSharedMem) X Sock_Close(&iSocketFD); X } X X else { X /** setup connection record **/ X X bcopy(pDest, &pNewNode->destRec, sizeof(TUid)); X X if (bSharedMem) { X pNewNode->iConnType = TALK_SHMEM_CONN; X } X else { X pNewNode->iSocketFD = iSocketFD; X pNewNode->iConnType = TALK_SOCK_CONN; X } X X pNewNode->pMessageQ = nil; X X X X /** return the address of record **/ X X *hSpeakNode = pNewNode; X } X } X X return(iErr); X X } /* Talk_NewSpeakConnection */ X/****************************************************************************************/ X X X X X/****************************************************************************************/ XTVeosErr Talk_KillSpeakConnection(pDeadNode) X TPSpeakNode pDeadNode; X{ X TVeosErr iErr; X TPMessageNode pMessageFinger, pTempLink; X X iErr = VEOS_FAILURE; X X if (pDeadNode) { /* sane? */ X X if (pDeadNode->iConnType == TALK_SOCK_CONN) { X X if (TALK_BUGS) X fprintf(stderr, "speak %s: closing connection on socket: %d\n", X WHOAMI, pDeadNode->iSocketFD); X X X /** close the speak connection **/ X X iErr = Sock_Close(&pDeadNode->iSocketFD); X } X X X if (TALK_BUGS) X fprintf(stderr, "speak %s: closed speak connection, talk: %d, sys: %d\n", X WHOAMI, iErr, errno); X X X /** deallocate queued messages nodes **/ X X pMessageFinger = pDeadNode->pMessageQ; X while (pMessageFinger) { X X DUMP(pMessageFinger->sMessage); X X pTempLink = pMessageFinger->pLink; X Shell_ReturnBlock(pMessageFinger, sizeof(TMessageNode), "message node"); X X pMessageFinger = pTempLink; X } X X X /** free allocated node **/ X X Shell_ReturnBlock(pDeadNode, sizeof(TSpeakNode), "speak node"); X X X iErr = VEOS_SUCCESS; X } X X return(iErr); X X } /* Talk_killSpeakConnection */ X/****************************************************************************************/ X X X X X/**************************************************************************************** X * Talk_RetrieveMessages */ X XTVeosErr Talk_RetrieveMessages(iSocketFD) X int iSocketFD; X{ X TVeosErr iErr; X int iBufferSize, iMsgLen, iBytesRead; X TMsgRec pbMsg; X char *pFinger; X X /** grab each waiting message in buffer **/ X X do { X X /** read size of next message from FD **/ X X iBufferSize = sizeof(int); X X iErr = Sock_Receive(iSocketFD, &iMsgLen, &iBufferSize); X if (iErr == VEOS_SUCCESS) { X X iMsgLen = ntohl(iMsgLen); X#ifndef OPTIMAL X if (TALK_BUGS) X fprintf(stderr, "listen %s: incoming message size: %d\n", X WHOAMI, iMsgLen); X#endif X /** read actual grouple message **/ X X iBytesRead = 0, pFinger = TALK_BUFFER; X while (iErr == VEOS_SUCCESS) { X X iBufferSize = iMsgLen - iBytesRead; X iErr = Sock_Receive(iSocketFD, pFinger, &iBufferSize); X#ifndef OPTIMAL X if (TALK_BUGS) { X fprintf(stderr, "listen %s: receive returned %d bytes, talk: %d, sys: %d\n", X WHOAMI, iBufferSize, iErr, errno); X } X#endif X if (iErr == VEOS_SUCCESS) { X X iBytesRead += iBufferSize; X pFinger += iBufferSize; X X if (iBytesRead == iMsgLen) { X pbMsg.iLen = iBytesRead; X pbMsg.sMessage = TALK_BUFFER; X X (*TALK_MSG_FUNC) (&pbMsg); X break; X } X } X X /** spin and wait for remaining data. X ** there is a minimal possibility of deadlock X ** introduced here. X ** situations that may cause spinning to deadlock: X ** 1. sending an oversized message to yourself. X ** 2. sending an oversized message to a process X ** that is simultaneously sending an oversized X ** message to you. X ** Assumption: oversized messages are infrequent. X **/ X else if (iBytesRead > 0 && iErr == TALK_LISTEN_BLOCKED) { X#ifndef OPTIMAL X if (TALK_BUGS) X fprintf(stderr, "listen %s: spinning on partial message..\n", WHOAMI); X#endif X iErr = VEOS_SUCCESS; X } X } X } X X } while (iErr == VEOS_SUCCESS); X X return(iErr); X X } /* Talk_RetrieveMessages */ X/****************************************************************************************/ X X X X/**************************************************************************************** X * Talk_ThrowMessages */ X XTVeosErr Talk_ThrowMessages(pSpeakNode, pDirty) X TPSpeakNode pSpeakNode; X boolean *pDirty; X{ X TVeosErr iErr = VEOS_FAILURE; X X *pDirty = FALSE; X X if (pSpeakNode->pMessageQ) { /* any messages? */ X X if (pSpeakNode->iConnType == TALK_SOCK_CONN) X iErr = Talk_SendMsgsOverNet(pSpeakNode); X X else if (pSpeakNode->iConnType == TALK_SHMEM_CONN) X iErr = ShMem_WriteMessages(pSpeakNode); X X X /** mark this connection for pending messages **/ X X if (pSpeakNode->pMessageQ) X *pDirty = TRUE; X } X X return(iErr); X X } /* Talk_ThrowMessages */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Talk_SendMsgsOverNet(pSpeakNode) X TPSpeakNode pSpeakNode; X{ X int iLen, iMsgLen, iBytesWritten; X TPMessageNode pSaveLink; X char *pFinger; X int iSocketFD; X TVeosErr iErr = VEOS_SUCCESS; X X iSocketFD = pSpeakNode->iSocketFD; X X /** dispatch message sending... X ** oldest jobs first to enforce sequencing X **/ X X do { X /** attempt to transmit oldest message **/ X X pFinger = pSpeakNode->pMessageQ->sMessage; X iMsgLen = pSpeakNode->pMessageQ->iMsgLen; X iBytesWritten = 0; X X while (iErr == VEOS_SUCCESS) { X X X /** transmit the message **/ X X iLen = iMsgLen - iBytesWritten; X iErr = Sock_Transmit(iSocketFD, pFinger, &iLen); X#ifndef OPTIMAL X if (TALK_BUGS) { X fprintf(stderr, "speak %s: transmit sent %d bytes, talk: %d, sys: %d\n", X WHOAMI, iLen, iErr, errno); X } X#endif X X if (iErr == VEOS_SUCCESS) { X X iBytesWritten += iLen; X pFinger += iLen; X X if (iBytesWritten == iMsgLen) { X X /** dequeue this message from connection record **/ X X DUMP(pSpeakNode->pMessageQ->sMessage); X X pSaveLink = pSpeakNode->pMessageQ->pLink; X Shell_ReturnBlock(pSpeakNode->pMessageQ, X sizeof(TMessageNode), "message node"); X pSpeakNode->pMessageQ = pSaveLink; X X break; X } X } X X /** spin and wait for line to free. X ** there is a minimal possibility of deadlock X ** introduced here. X ** situations that may cause spinning to deadlock: X ** 1. sending an oversized message to yourself. X ** 2. sending an oversized message to a process X ** that is simultaneously sending an oversized X ** message to you. X ** Assumption: oversized messages are infrequent. X **/ X else if (iBytesWritten > 0 && iErr == TALK_SPEAK_BLOCKED) { X#ifndef OPTIMAL X if (TALK_BUGS) X fprintf(stderr, "speak %s: spinning on partial message..\n", WHOAMI); X#endif X iErr = VEOS_SUCCESS; X } X X } /* while more to write */ X X X } while (pSpeakNode->pMessageQ); X X return(iErr); X X } /* Talk_SendMsgsOverNet */ X/****************************************************************************************/ X X X X/**************************************************************************************** X * Talk_AddSpeakJob */ X XTVeosErr Talk_AddSpeakJob(pDestNode, pMsgBlock) X TPSpeakNode pDestNode; X TPMsgRec pMsgBlock; X{ X TVeosErr iErr; X TPMessageNode pNewJob; X THMessageNode hFinger; X X /** allocate new outgoing message job record **/ X X iErr = Shell_NewBlock(sizeof(TMessageNode), &pNewJob, "message node"); X if (iErr == VEOS_SUCCESS) { X X X /** setup job record **/ X X if (NEWPTR(pNewJob->sMessage, char *, pMsgBlock->iLen + 4)) { X X /** insert length code at front of message **/ X *(long *) pNewJob->sMessage = htonl(pMsgBlock->iLen); X X bcopy(pMsgBlock->sMessage, pNewJob->sMessage + 4, pMsgBlock->iLen); X pNewJob->iMsgLen = pMsgBlock->iLen + 4; X pNewJob->pLink = nil; X X /** append new job to destination's message queue **/ X X hFinger = &pDestNode->pMessageQ; X while (*hFinger) X hFinger = &(*hFinger)->pLink; X X *hFinger = pNewJob; X X iErr = VEOS_SUCCESS; X } X } X X X if (iErr != VEOS_SUCCESS) { X X /** cleanup any mess **/ X X if (pNewJob) { X if (pNewJob->sMessage) X DUMP(pNewJob->sMessage); X Shell_ReturnBlock(pNewJob, sizeof(TMessageNode), "message node"); X } X } X X return(iErr); X X } /* Talk_AddSpeakJob */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Talk_DummyMsgHandler(pMsgRec) X TPMsgRec pMsgRec; X{ X char *pBuf; X X if (TALK_BUGS) { X fprintf(stderr, "listen %s: message not converted.\n", WHOAMI); X } X X return(VEOS_SUCCESS); X X } /* Talk_DummyMsgHandler */ X/****************************************************************************************/ X X X#ifdef banana Xint Talk_ConnectTrap(); X X/****************************************************************************************/ Xint Talk_ConnectTrap(iSignal, iCode, context, pAddr) X int iSignal, iCode; X struct sigcontext *context; X char *pAddr; X{ X if (iSignal == SIGIO) X NEW_CONN = TRUE; X X return(0); X } X/****************************************************************************************/ X#endif X X X X X X X X END_OF_FILE if test 24919 -ne `wc -c <'kernel_private/src/talk/talk.c'`; then echo shar: \"'kernel_private/src/talk/talk.c'\" unpacked with wrong size! fi # end of 'kernel_private/src/talk/talk.c' fi if test -f 'src/kernel_current/talk/talk.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/kernel_current/talk/talk.c'\" else echo shar: Extracting \"'src/kernel_current/talk/talk.c'\" \(24919 characters\) sed "s/^X//" >'src/kernel_current/talk/talk.c' <<'END_OF_FILE' X/**************************************************************************************** X * * X * file: talk.c * X * * X * October 20, 1990: an entity's network interface to other entities. * X * * X * this library represents the presentation & session layers of the * X * ISO network systems model. * X * * X * the network and transport layers provided by socket.c * X * * X * by Geoffrey P. Coco at the HITLab, Seattle. * X * * X ****************************************************************************************/ X X X/**************************************************************************************** X * Copyright (C) 1992 Geoffrey P. Coco, Human Interface Technology Lab, Seattle * X ****************************************************************************************/ X X X/**************************************************************************************** X Preliminaries X ****************************************************************************************/ X X#include "kernel.h" X#include "errno.h" X#include "sys/signal.h" X X/****************************************************************************************/ X XTVeosErr Talk_DummyMsgHandler(); X X/****************************************************************************************/ X X X X/**************************************************************************************** X * Talk_HelloTalk * X * * X * talk initialization. call Talk_HelloTalk() once, and don't proceed upon failure. */ X XTVeosErr Talk_HelloTalk(iPort, pMessFun) X int iPort; X TVeosErr (*pMessFun) (); X{ X TVeosErr iErr; X X X /** allocate fast message buffers **/ X X iErr = VEOS_MEM_ERR; X if (NEWPTR(TALK_BUFFER, char *, TALK_MAX_BUFFER)) { X X X /** initialize cache settings **/ X X SPEAK_SET = nil; X X LISTEN_SOCKETFD = TALK_BOGUS_FD; X LISTEN_SET = nil; X X FD_ZERO(&OPEN_READ_SOCKETS); X FD_ZERO(&OPEN_WRITE_SOCKETS); X X TALK_MSG_FUNC = pMessFun ? pMessFun : Talk_DummyMsgHandler; X X bzero(SOCK_HOSTS, 26 * sizeof(TPHostNode)); X X X /** initialize public cache settings **/ X X SPEAK_DIRTY = FALSE; X X X X /** initialize listen connection **/ X X iErr = Talk_OpenPort(iPort); X } X X return(iErr); X X } /* Talk_HelloTalk */ X/****************************************************************************************/ X X X X X/**************************************************************************************** X * Talk_ByeTalk * X * * X * cleanup network and memory allocation only after finished using talk library. */ X XTVeosErr Talk_ByeTalk() X{ X TPSpeakNode pSpeakFinger, pTempSpeak; X TPListenNode pListenFinger, pTempListen; X X /** take down listen port **/ X X Talk_ClosePort(); X X X /** close all speak connections **/ X X pSpeakFinger = SPEAK_SET; X while (pSpeakFinger) { X X pTempSpeak = pSpeakFinger->pLink; X X Talk_KillSpeakConnection(pSpeakFinger); X X pSpeakFinger = pTempSpeak; X } X X X /** close listen connections (normal mechanism is while attempting to read) **/ X X pListenFinger = LISTEN_SET; X while (pListenFinger) { X X pTempListen = pListenFinger->pLink; X X Talk_KillListenConnection(pListenFinger); X X pListenFinger = pTempListen; X } X X X /** deallocate local library cache **/ X X if (TALK_BUFFER) X DUMP(TALK_BUFFER); X X X return(VEOS_SUCCESS); X X } /* Talk_ByeTalk */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Talk_SpeakToMany(pDests, pMsg) X TPUidNode pDests; X TPMsgRec pMsg; X{ X TVeosErr iErr; X TPUidNode pFinger; X X iErr = VEOS_FAILURE; X X if (pDests && pMsg) { X X iErr = VEOS_SUCCESS; X X pFinger = pDests; X while (pFinger && iErr == VEOS_SUCCESS) { X X iErr = Talk_PostSpeakMessage(&pFinger->addr, pMsg); X X pFinger = pFinger->pNext; X } X } X X return(iErr); X X } /* Talk_SpeakToMany */ X/****************************************************************************************/ X X X X/**************************************************************************************** X * private functions * X ****************************************************************************************/ X X X/**************************************************************************************** X * Talk_OpenPort * X * * X * establish an incoming message gateway for the entity client. * X * Talk_OpenPort() should be paired with a call to Talk_ClosePort(). */ X XTVeosErr Talk_OpenPort(iPort) X int iPort; X{ X TVeosErr iErr; X boolean bFound; X X X /** install entity connection handler **/ X/* X signal(SIGIO, Talk_ConnectTrap); X*/ X X X /** initiate network comminication. alert world of our existence. **/ X X if (TALK_BUGS) X fprintf(stderr, "listen %s: trying to listen...\n", WHOAMI); X X X if (iPort != TALK_BOGUS_PORT) { X X /** use chosen port number **/ X X iErr = Sock_Listen(&LISTEN_SOCKETFD, X iPort, X "tcp", X TALK_AGRESSIVE); X } X else { X /** try all sockets until we find an unused one **/ X X iPort = TALK_MIN_PORT; X iErr = VEOS_FAILURE; X X while (iErr != VEOS_SUCCESS && X iPort < TALK_MAX_PORT) { X X iErr = Sock_Listen(&LISTEN_SOCKETFD, X iPort, X "tcp", X TALK_PASSIVE); X if (iErr != VEOS_SUCCESS) X iPort ++; X } X } X X X if (iErr != VEOS_SUCCESS) { X if (TALK_BUGS) X fprintf(stderr, "listen %s: cannot listen, talk: %d, sys: %d\n", X WHOAMI, iErr, errno); X } X X else { X /** maintain references to entity uid **/ X X IDENT_ADDR.iPort = iPort; X Shell_UpdateUid(); X X if (TALK_BUGS) X fprintf(stderr, "listen %s: successful listen\n", WHOAMI); X X X /** setup shared memory channel **/ X X iErr = ShMem_Init(); X } X X return(iErr); X X } /* Talk_OpenPort */ X/****************************************************************************************/ X X X X/**************************************************************************************** X * Talk_ClosePort * X * * X * close the incoming message gateway. the cleanup counterpart to Talk_OpenTalk(). */ X XTVeosErr Talk_ClosePort() X{ X TVeosErr iErr; X X X /** unregister ourselves from net **/ X X if (TALK_BUGS) X fprintf(stderr, "listen %s: about to close main listen socket: %d, sys: %d\n", X WHOAMI, LISTEN_SOCKETFD, errno); X X X iErr = Sock_Close(&LISTEN_SOCKETFD); X X if (TALK_BUGS) X fprintf(stderr, "listen %s: closed main listen port, talk: %d, sys: %d\n", X WHOAMI, iErr, errno); X X X /** takedown shared memory channel **/ X X ShMem_Close(); X X X return(iErr); X X } /* Talk_ClosePort */ X/****************************************************************************************/ X X X X X/****************************************************************************************/ XTVeosErr Talk_GatherListenMessages() X{ X TVeosErr iErr; X int iSocketFD; X THListenNode hListenFinger; X TPListenNode pSaveLink; X X X hListenFinger = &LISTEN_SET; X X while (*hListenFinger) { X X pSaveLink = *hListenFinger; X iSocketFD = (*hListenFinger)->iSocketFD; X X X /** attempt to read messages from the connection **/ X X iErr = Talk_RetrieveMessages(iSocketFD); X if (iErr != TALK_CONN_CLOSED) X X hListenFinger = &(*hListenFinger)->pLink; X X X else { X /** connection was lost from other end **/ X X if (TALK_BUGS) X fprintf(stderr, "listen %s: lost connection on socket: %d\n", X WHOAMI, iSocketFD); X X pSaveLink = (*hListenFinger)->pLink; X X Talk_KillListenConnection(*hListenFinger); X X *hListenFinger = pSaveLink; X } X } X X X /** all shared memory messages come in through one channel **/ X X ShMem_GatherMessages(); X X X return(iErr); X X } /* Talk_GatherListenMessages */ X/****************************************************************************************/ X X X X X/**************************************************************************************** X * Talk_EstNewListenConnections */ X XTVeosErr Talk_EstNewListenConnections() X{ X TVeosErr iErr = VEOS_SUCCESS; X TPListenNode pNewNode; X X iErr = Talk_NewListenConnection(LISTEN_SOCKETFD, &pNewNode); X if (iErr == VEOS_SUCCESS) { X X /** store this record locally **/ X X pNewNode->pLink = LISTEN_SET; X LISTEN_SET = pNewNode; X } X X return(VEOS_SUCCESS); X X } /* Talk_EstNewListenConnections */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Talk_DispatchQedSpeakMessages() X{ X TVeosErr iErr; X THSpeakNode hSpeakFinger; X TPSpeakNode pSaveLink; X boolean bLocalDirty; X X iErr = VEOS_SUCCESS; X X X /** inspect every open connection for queued outgoing messages **/ X X hSpeakFinger = &SPEAK_SET; X SPEAK_DIRTY = FALSE; X X while (*hSpeakFinger) { X X X /** attempt to send queued messages for this connection in order **/ X X iErr = Talk_ThrowMessages(*hSpeakFinger, &bLocalDirty); X if (iErr == TALK_CONN_CLOSED) { X X X /** connection was lost from other end **/ X X if (TALK_BUGS) X fprintf(stderr, "speak %s: lost connection to (%d %d) on socket: %d\n", X WHOAMI, X (*hSpeakFinger)->destRec.lHost, X (*hSpeakFinger)->destRec.iPort, X (*hSpeakFinger)->iSocketFD); X X pSaveLink = (*hSpeakFinger)->pLink; X X Talk_KillSpeakConnection(*hSpeakFinger); X X *hSpeakFinger = pSaveLink; X } X X else { X if (bLocalDirty) X SPEAK_DIRTY = TRUE; X X X /** check next connection **/ X X hSpeakFinger = &(*hSpeakFinger)->pLink; X } X } X X return(iErr); X X } /* Talk_DispatchQedSpeakMessages */ X/****************************************************************************************/ X X X X X/**************************************************************************************** X * Talk_NewListenConnection */ X XTVeosErr Talk_NewListenConnection(iListenSocketFD, hListenNode) X int iListenSocketFD; X THListenNode hListenNode; X{ X TPListenNode pNewNode; X TVeosErr iErr; X int iSocketFD; X X X iErr = Sock_ReadSelect(iListenSocketFD); X if (iErr == VEOS_SUCCESS) { X X if (TALK_BUGS) X fprintf(stderr, "listen %s: another entity is trying to connect...\n", X WHOAMI); X X /** establish a full-duplex connection **/ X X iErr = Sock_Accept(iListenSocketFD, &iSocketFD); X X if (iErr != VEOS_SUCCESS) X perror("talk: _Accept"); X X else { X X if (TALK_BUGS) X fprintf(stderr, "listen %s: another entity connected on socket: %d\n", X WHOAMI, iSocketFD); X X /** allocate listen connection record **/ X X iErr = Shell_NewBlock(sizeof(TListenNode), &pNewNode, "listen node"); X if (iErr != VEOS_SUCCESS) { X X Sock_Close(&iSocketFD); X } X X else { X /** setup connection record **/ X X pNewNode->iSocketFD = iSocketFD; X pNewNode->pLink = nil; X X *hListenNode = pNewNode; X } X } X } X X return(iErr); X X } /* Talk_NewListenConnection */ X/****************************************************************************************/ X X X X X/****************************************************************************************/ XTVeosErr Talk_KillListenConnection(pDeadNode) X TPListenNode pDeadNode; X{ X TVeosErr iErr; X X iErr = VEOS_FAILURE; X X if (pDeadNode) { /* sane? */ X X if (TALK_BUGS) X fprintf(stderr, "listen %s: closing connection on socket: %d\n", X WHOAMI, pDeadNode->iSocketFD); X X /** strike this connection in all respects **/ X X iErr = Sock_Close(&pDeadNode->iSocketFD); X X X if (TALK_BUGS) X fprintf(stderr, "listen %s: closed listen connection, talk: %d, sys: %d\n", X WHOAMI, iErr, errno); X X X Shell_ReturnBlock(pDeadNode, sizeof(TListenNode), "listen node"); X X iErr = VEOS_SUCCESS; X } X X return(iErr); X X } /* Talk_KillListenConnection */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Talk_PostSpeakMessage(pDest, pMsgBlock) X TPUid pDest; X TPMsgRec pMsgBlock; X{ X TVeosErr iErr; X TPSpeakNode pDestNode, pSaveLink; X THSpeakNode hFinger; X boolean bLocalDirty; X X if (pDest) { X X X /** do we already have a connection to this destination? **/ X X hFinger = &SPEAK_SET; X iErr = VEOS_FAILURE; X X while (*hFinger && iErr != VEOS_SUCCESS) { X X if (UID_COMPARE(&(*hFinger)->destRec, pDest)) { X X pDestNode = *hFinger; X iErr = VEOS_SUCCESS; X } X else X hFinger = &(*hFinger)->pLink; X } X X X /** attempt to connect to this destaination for the first time **/ X X if (iErr != VEOS_SUCCESS) { X iErr = Talk_NewSpeakConnection(pDest, X &pDestNode); X if (iErr == VEOS_SUCCESS) { X X /** add connection record to local list **/ X X pDestNode->pLink = SPEAK_SET; X SPEAK_SET = pDestNode; X hFinger = &SPEAK_SET; X } X } X X X /** add new message to this connection's queue **/ X X if (iErr == VEOS_SUCCESS) { X iErr = Talk_AddSpeakJob(pDestNode, pMsgBlock); X if (iErr == VEOS_SUCCESS) { X X X /** attempt to send this message right now **/ X X iErr = Talk_ThrowMessages(pDestNode, &bLocalDirty); X if (iErr == TALK_CONN_CLOSED) { X X X /** connection was lost from other end **/ X X if (TALK_BUGS) X fprintf(stderr, "speak %s: lost connection to (%d %d) on socket: %d\n", X WHOAMI, X pDestNode->destRec.lHost, X pDestNode->destRec.iPort, X pDestNode->iSocketFD); X X X pSaveLink = pDestNode->pLink; X X Talk_KillSpeakConnection(pDestNode); X X *hFinger = pSaveLink; X } X X else if (bLocalDirty) X SPEAK_DIRTY = TRUE; X } X } X } X X return(iErr); X X } /* Talk_PostSpeakMessage */ X/****************************************************************************************/ X X X X/**************************************************************************************** X * Talk_NewSpeakConnection */ X XTVeosErr Talk_NewSpeakConnection(pDest, hSpeakNode) X TPUid pDest; X THSpeakNode hSpeakNode; X{ X TPSpeakNode pNewNode; X int iSocketFD; X TPSharedRec pChannel; X TVeosErr iErr; X boolean bSharedMem; X X *hSpeakNode = nil; X X X /** try to connect to destination shell **/ X X if (TALK_BUGS) X fprintf(stderr, "speak %s: trying to connect to entity: (%d %d)\n", X WHOAMI, pDest->lHost, pDest->iPort); X X X /** special case communications - shared memory **/ X X bSharedMem = ShMem_CanShareMem(pDest); X X if (bSharedMem) { X iErr = ShMem_FindChannel(pDest->iPort, &pChannel); X } X else { X iErr = Sock_Connect(&iSocketFD, X pDest, X TALK_DEFAULT_PROTOCOL); X } X X X if (iErr != VEOS_SUCCESS) { X X if (TALK_BUGS) X fprintf(stderr, "speak %s: cannot connect, talk: %d, sys: %d\n", X WHOAMI, iErr, errno); X X iErr = VEOS_FAILURE; X } X X else { X X if (TALK_BUGS) X fprintf(stderr, "speak %s: connected to entity: (%d %d) on socket: %d\n", X WHOAMI, pDest->lHost, pDest->iPort, iSocketFD); X X X /** allocate a new connection record **/ X X iErr = Shell_NewBlock(sizeof(TSpeakNode), &pNewNode, "speak node"); X if (iErr != VEOS_SUCCESS) { X X if (!bSharedMem) X Sock_Close(&iSocketFD); X } X X else { X /** setup connection record **/ X X bcopy(pDest, &pNewNode->destRec, sizeof(TUid)); X X if (bSharedMem) { X pNewNode->iConnType = TALK_SHMEM_CONN; X } X else { X pNewNode->iSocketFD = iSocketFD; X pNewNode->iConnType = TALK_SOCK_CONN; X } X X pNewNode->pMessageQ = nil; X X X X /** return the address of record **/ X X *hSpeakNode = pNewNode; X } X } X X return(iErr); X X } /* Talk_NewSpeakConnection */ X/****************************************************************************************/ X X X X X/****************************************************************************************/ XTVeosErr Talk_KillSpeakConnection(pDeadNode) X TPSpeakNode pDeadNode; X{ X TVeosErr iErr; X TPMessageNode pMessageFinger, pTempLink; X X iErr = VEOS_FAILURE; X X if (pDeadNode) { /* sane? */ X X if (pDeadNode->iConnType == TALK_SOCK_CONN) { X X if (TALK_BUGS) X fprintf(stderr, "speak %s: closing connection on socket: %d\n", X WHOAMI, pDeadNode->iSocketFD); X X X /** close the speak connection **/ X X iErr = Sock_Close(&pDeadNode->iSocketFD); X } X X X if (TALK_BUGS) X fprintf(stderr, "speak %s: closed speak connection, talk: %d, sys: %d\n", X WHOAMI, iErr, errno); X X X /** deallocate queued messages nodes **/ X X pMessageFinger = pDeadNode->pMessageQ; X while (pMessageFinger) { X X DUMP(pMessageFinger->sMessage); X X pTempLink = pMessageFinger->pLink; X Shell_ReturnBlock(pMessageFinger, sizeof(TMessageNode), "message node"); X X pMessageFinger = pTempLink; X } X X X /** free allocated node **/ X X Shell_ReturnBlock(pDeadNode, sizeof(TSpeakNode), "speak node"); X X X iErr = VEOS_SUCCESS; X } X X return(iErr); X X } /* Talk_killSpeakConnection */ X/****************************************************************************************/ X X X X X/**************************************************************************************** X * Talk_RetrieveMessages */ X XTVeosErr Talk_RetrieveMessages(iSocketFD) X int iSocketFD; X{ X TVeosErr iErr; X int iBufferSize, iMsgLen, iBytesRead; X TMsgRec pbMsg; X char *pFinger; X X /** grab each waiting message in buffer **/ X X do { X X /** read size of next message from FD **/ X X iBufferSize = sizeof(int); X X iErr = Sock_Receive(iSocketFD, &iMsgLen, &iBufferSize); X if (iErr == VEOS_SUCCESS) { X X iMsgLen = ntohl(iMsgLen); X#ifndef OPTIMAL X if (TALK_BUGS) X fprintf(stderr, "listen %s: incoming message size: %d\n", X WHOAMI, iMsgLen); X#endif X /** read actual grouple message **/ X X iBytesRead = 0, pFinger = TALK_BUFFER; X while (iErr == VEOS_SUCCESS) { X X iBufferSize = iMsgLen - iBytesRead; X iErr = Sock_Receive(iSocketFD, pFinger, &iBufferSize); X#ifndef OPTIMAL X if (TALK_BUGS) { X fprintf(stderr, "listen %s: receive returned %d bytes, talk: %d, sys: %d\n", X WHOAMI, iBufferSize, iErr, errno); X } X#endif X if (iErr == VEOS_SUCCESS) { X X iBytesRead += iBufferSize; X pFinger += iBufferSize; X X if (iBytesRead == iMsgLen) { X pbMsg.iLen = iBytesRead; X pbMsg.sMessage = TALK_BUFFER; X X (*TALK_MSG_FUNC) (&pbMsg); X break; X } X } X X /** spin and wait for remaining data. X ** there is a minimal possibility of deadlock X ** introduced here. X ** situations that may cause spinning to deadlock: X ** 1. sending an oversized message to yourself. X ** 2. sending an oversized message to a process X ** that is simultaneously sending an oversized X ** message to you. X ** Assumption: oversized messages are infrequent. X **/ X else if (iBytesRead > 0 && iErr == TALK_LISTEN_BLOCKED) { X#ifndef OPTIMAL X if (TALK_BUGS) X fprintf(stderr, "listen %s: spinning on partial message..\n", WHOAMI); X#endif X iErr = VEOS_SUCCESS; X } X } X } X X } while (iErr == VEOS_SUCCESS); X X return(iErr); X X } /* Talk_RetrieveMessages */ X/****************************************************************************************/ X X X X/**************************************************************************************** X * Talk_ThrowMessages */ X XTVeosErr Talk_ThrowMessages(pSpeakNode, pDirty) X TPSpeakNode pSpeakNode; X boolean *pDirty; X{ X TVeosErr iErr = VEOS_FAILURE; X X *pDirty = FALSE; X X if (pSpeakNode->pMessageQ) { /* any messages? */ X X if (pSpeakNode->iConnType == TALK_SOCK_CONN) X iErr = Talk_SendMsgsOverNet(pSpeakNode); X X else if (pSpeakNode->iConnType == TALK_SHMEM_CONN) X iErr = ShMem_WriteMessages(pSpeakNode); X X X /** mark this connection for pending messages **/ X X if (pSpeakNode->pMessageQ) X *pDirty = TRUE; X } X X return(iErr); X X } /* Talk_ThrowMessages */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Talk_SendMsgsOverNet(pSpeakNode) X TPSpeakNode pSpeakNode; X{ X int iLen, iMsgLen, iBytesWritten; X TPMessageNode pSaveLink; X char *pFinger; X int iSocketFD; X TVeosErr iErr = VEOS_SUCCESS; X X iSocketFD = pSpeakNode->iSocketFD; X X /** dispatch message sending... X ** oldest jobs first to enforce sequencing X **/ X X do { X /** attempt to transmit oldest message **/ X X pFinger = pSpeakNode->pMessageQ->sMessage; X iMsgLen = pSpeakNode->pMessageQ->iMsgLen; X iBytesWritten = 0; X X while (iErr == VEOS_SUCCESS) { X X X /** transmit the message **/ X X iLen = iMsgLen - iBytesWritten; X iErr = Sock_Transmit(iSocketFD, pFinger, &iLen); X#ifndef OPTIMAL X if (TALK_BUGS) { X fprintf(stderr, "speak %s: transmit sent %d bytes, talk: %d, sys: %d\n", X WHOAMI, iLen, iErr, errno); X } X#endif X X if (iErr == VEOS_SUCCESS) { X X iBytesWritten += iLen; X pFinger += iLen; X X if (iBytesWritten == iMsgLen) { X X /** dequeue this message from connection record **/ X X DUMP(pSpeakNode->pMessageQ->sMessage); X X pSaveLink = pSpeakNode->pMessageQ->pLink; X Shell_ReturnBlock(pSpeakNode->pMessageQ, X sizeof(TMessageNode), "message node"); X pSpeakNode->pMessageQ = pSaveLink; X X break; X } X } X X /** spin and wait for line to free. X ** there is a minimal possibility of deadlock X ** introduced here. X ** situations that may cause spinning to deadlock: X ** 1. sending an oversized message to yourself. X ** 2. sending an oversized message to a process X ** that is simultaneously sending an oversized X ** message to you. X ** Assumption: oversized messages are infrequent. X **/ X else if (iBytesWritten > 0 && iErr == TALK_SPEAK_BLOCKED) { X#ifndef OPTIMAL X if (TALK_BUGS) X fprintf(stderr, "speak %s: spinning on partial message..\n", WHOAMI); X#endif X iErr = VEOS_SUCCESS; X } X X } /* while more to write */ X X X } while (pSpeakNode->pMessageQ); X X return(iErr); X X } /* Talk_SendMsgsOverNet */ X/****************************************************************************************/ X X X X/**************************************************************************************** X * Talk_AddSpeakJob */ X XTVeosErr Talk_AddSpeakJob(pDestNode, pMsgBlock) X TPSpeakNode pDestNode; X TPMsgRec pMsgBlock; X{ X TVeosErr iErr; X TPMessageNode pNewJob; X THMessageNode hFinger; X X /** allocate new outgoing message job record **/ X X iErr = Shell_NewBlock(sizeof(TMessageNode), &pNewJob, "message node"); X if (iErr == VEOS_SUCCESS) { X X X /** setup job record **/ X X if (NEWPTR(pNewJob->sMessage, char *, pMsgBlock->iLen + 4)) { X X /** insert length code at front of message **/ X *(long *) pNewJob->sMessage = htonl(pMsgBlock->iLen); X X bcopy(pMsgBlock->sMessage, pNewJob->sMessage + 4, pMsgBlock->iLen); X pNewJob->iMsgLen = pMsgBlock->iLen + 4; X pNewJob->pLink = nil; X X /** append new job to destination's message queue **/ X X hFinger = &pDestNode->pMessageQ; X while (*hFinger) X hFinger = &(*hFinger)->pLink; X X *hFinger = pNewJob; X X iErr = VEOS_SUCCESS; X } X } X X X if (iErr != VEOS_SUCCESS) { X X /** cleanup any mess **/ X X if (pNewJob) { X if (pNewJob->sMessage) X DUMP(pNewJob->sMessage); X Shell_ReturnBlock(pNewJob, sizeof(TMessageNode), "message node"); X } X } X X return(iErr); X X } /* Talk_AddSpeakJob */ X/****************************************************************************************/ X X X X/****************************************************************************************/ XTVeosErr Talk_DummyMsgHandler(pMsgRec) X TPMsgRec pMsgRec; X{ X char *pBuf; X X if (TALK_BUGS) { X fprintf(stderr, "listen %s: message not converted.\n", WHOAMI); X } X X return(VEOS_SUCCESS); X X } /* Talk_DummyMsgHandler */ X/****************************************************************************************/ X X X#ifdef banana Xint Talk_ConnectTrap(); X X/****************************************************************************************/ Xint Talk_ConnectTrap(iSignal, iCode, context, pAddr) X int iSignal, iCode; X struct sigcontext *context; X char *pAddr; X{ X if (iSignal == SIGIO) X NEW_CONN = TRUE; X X return(0); X } X/****************************************************************************************/ X#endif X X X X X X X X END_OF_FILE if test 24919 -ne `wc -c <'src/kernel_current/talk/talk.c'`; then echo shar: \"'src/kernel_current/talk/talk.c'\" unpacked with wrong size! fi # end of 'src/kernel_current/talk/talk.c' fi echo shar: End of archive 11 \(of 16\). cp /dev/null ark11isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 16 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0