Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

273 lines
8.0 KiB

  1. // ---------------------------------------------------------------------------
  2. //
  3. // Message Queue functions
  4. //
  5. // ---------------------------------------------------------------------------
  6. /*
  7. Message Queue:
  8. Allow 2 script threads to send async messages to each other
  9. and receive async replies.
  10. First thread creates the Q, second thread obtains the Q
  11. via GetMsgQueue()
  12. Creator thread gets the "left" Q, and other thread gets "right" Q
  13. Internally it uses associative arrays as msg queues.
  14. Methods:
  15. WaitForMsgAndDispatch(strOtherWaitEvents, fnMsgProc, nTimeout)
  16. You should call this function instead of calling WaitForSync()
  17. or WaitForMultipleSyncs(). It waits for messages from this Queue.
  18. strOtherWaitEvents: Syncs you want to wait on.
  19. fnMsgProc: Message dispatch function. The prototype is:
  20. fnMsgProc(queue, msg);
  21. Where "queue" is the queue which received the msg,
  22. and msg is a copy of the array of arguments sent
  23. via SendMessage(). (The array is copied, not the args).
  24. nTimeout: Same as WaitForSync(). 0 for INFINITE.
  25. Return value is the same as WaitForMultipleSyncs().
  26. SendMessage(strCmd, ...)
  27. Send a message to the other thread. "strCmd" and all other arguments
  28. are passed as is to the other thread.
  29. Returns a reference to the message. Save this if you would like
  30. to wait for the message to be processed.
  31. WaitForMsg(msg, nTimeout)
  32. Wait patiently until after the message has been processed.
  33. msg: The msg as returned by SendMessage()
  34. nTimeout: Same as WaitForSync(). 0 for INFINITE.
  35. */
  36. function MsgQueue(strName)
  37. {
  38. {
  39. this.WaitForMsgAndDispatch = QueueWaitForMsgAndDispatch;
  40. this.SendMessage = QueueSendMessage;
  41. this.GetMessage = QueueGetMessage;
  42. this.Dispatch = QueueDispatch;
  43. this.WaitForMsg = QueueWaitForMsg;
  44. this.ReplyMessage = QueueReplyMessage;
  45. this.SignalThisThread = QueueSignalThreadSync;
  46. }
  47. //$ BUGBUG can contructors return failed? exception?
  48. if (strName == '')
  49. return false;
  50. this.strName = strName;
  51. this.nHighIndex = 0;
  52. this.nLowIndex = 0;
  53. this.aMsgs = new Array();
  54. this.strReplySignal = strName.split(',')[0] + 'Reply';
  55. if (arguments.length == 2) // Creating right-side Q for "other" side
  56. {
  57. this.otherQ = arguments[1];
  58. arguments[1].otherQ = this;
  59. this.strSignalName = strName.split(',')[0] + "Right";
  60. this.strSignalNameWait = strName.split(',')[0] + "Left";
  61. // now, exchange signalling functions
  62. this.SignalOtherThread = this.otherQ.SignalThisThread;
  63. this.otherQ.SignalOtherThread = this.SignalThisThread;
  64. }
  65. else
  66. {
  67. // Left Q specific initialization
  68. this.strSignalName = strName.split(',')[0] + "Left";
  69. this.strSignalNameWait = strName.split(',')[0] + "Right";
  70. }
  71. return this;
  72. }
  73. function GetMsgQueue(queue)
  74. {
  75. // sic: Add '' to the name to force a local copy of the string
  76. var newq = new MsgQueue(queue.strName + '', queue);
  77. LogMsg('GetMsgQueue ' + newq.strName);
  78. return newq;
  79. }
  80. function MsgPacket(nMsgIndex, aArgs)
  81. {
  82. this.nIndex = nMsgIndex;
  83. this.aArgs = new Array();
  84. this.nReplied = false;
  85. this.vReplyValue = 'ok';
  86. // Copy just the array elements of aArgs -- avoiding any other properties.
  87. for(var i = 0; i < aArgs.length; ++i)
  88. this.aArgs[i] = aArgs[i];
  89. }
  90. // MsgQueue Member functions
  91. function WaitForMultipleQueues(aQueues, strOtherWaitEvents, fnMsgProc, nTimeout)
  92. {
  93. var index;
  94. var strMyEvents = '';
  95. var nEvent = 0;
  96. var msg;
  97. var SignaledQueue;
  98. for(index = 0; index < aQueues.length; ++index)
  99. {
  100. if (strMyEvents == '')
  101. strMyEvents = aQueues[index].strSignalNameWait;
  102. else
  103. strMyEvents += ',' + aQueues[index].strSignalNameWait;
  104. }
  105. if (strOtherWaitEvents != '')
  106. strMyEvents += ',' + strOtherWaitEvents;
  107. do
  108. {
  109. nEvent = WaitForMultipleSyncs(strMyEvents, false, nTimeout);
  110. if (nEvent > aQueues.length)
  111. {
  112. return nEvent - aQueues.length;
  113. }
  114. if (nEvent > 0) // && nEvent <= aQueues.length)
  115. {
  116. SignaledQueue = aQueues[nEvent - 1];
  117. ResetSync(SignaledQueue.strSignalNameWait);
  118. while ( (msg = SignaledQueue.GetMessage()) != null)
  119. {
  120. SignaledQueue.Dispatch(msg, fnMsgProc);
  121. msg = null;
  122. }
  123. }
  124. } while(nEvent != 0);
  125. return nEvent; // 0 -- timeout
  126. }
  127. function QueueWaitForMsgAndDispatch(strOtherWaitEvents, fnMsgProc, nTimeout)
  128. {
  129. var strMyEvents = this.strSignalNameWait;
  130. if (strOtherWaitEvents != '')
  131. strMyEvents += ',' + strOtherWaitEvents;
  132. var nEvent = 0;
  133. var msg;
  134. do
  135. {
  136. var nEvent = WaitForMultipleSyncs(strMyEvents, false, nTimeout);
  137. if (nEvent == 1)
  138. {
  139. ResetSync(this.strSignalNameWait);
  140. while ( (msg = this.GetMessage()) != null)
  141. {
  142. this.Dispatch(msg, fnMsgProc);
  143. msg = null;
  144. }
  145. }
  146. } while(nEvent == 1);
  147. if (nEvent > 1) // adjust the event number to indicate which of their events happened
  148. --nEvent;
  149. return nEvent;
  150. }
  151. // Send a message to the "other" thread
  152. function QueueSendMessage(strCmd)
  153. {
  154. var msg = null;
  155. var n;
  156. LogMsg(this.strName + ': Sending message ' + strCmd);
  157. try
  158. {
  159. msg = new MsgPacket(this.nHighIndex, arguments);
  160. n = this.nHighIndex++;
  161. this.aMsgs[ n ] = msg;
  162. this.SignalOtherThread(this.strSignalName);
  163. }
  164. catch(ex)
  165. {
  166. LogMsg("QueueSendMessage(" + this.strName + ") failed: " + ex);
  167. }
  168. return msg;
  169. }
  170. // Retrieve message sent by "other" thread
  171. function QueueGetMessage()
  172. {
  173. var msg = null;
  174. try
  175. {
  176. LogMsg('getting message');
  177. if (this.otherQ.nHighIndex > this.otherQ.nLowIndex)
  178. {
  179. var n = this.otherQ.nLowIndex++;
  180. msg = this.otherQ.aMsgs[ n ];
  181. delete this.otherQ.aMsgs[ n ];
  182. }
  183. }
  184. catch(ex)
  185. {
  186. LogMsg("QueueGetMessage(" + this.strName + " failed: " + ex);
  187. }
  188. return msg;
  189. }
  190. function QueueDispatch(msg, fnMsgProc)
  191. {
  192. try
  193. {
  194. msg.vReplyValue = fnMsgProc(this, msg);
  195. }
  196. catch(ex)
  197. {
  198. LogMsg("Possible BUG: MessageQueue('" + this.strName + "') dispatch function threw " + ex);
  199. JAssert(g_fAssertOnDispatchException == false, "Possible BUG: MessageQueue('" + this.strName + "') dispatch function threw an exception");
  200. msg.vReplyValue = ex;
  201. }
  202. this.ReplyMessage(msg);
  203. }
  204. // Wait at least "nTimeout" miliseconds for a reply on the given msg.
  205. // Returns true if the message was replied to.
  206. function QueueWaitForMsg(msg, nTimeout)
  207. {
  208. while (!msg.nReplied)
  209. {
  210. WaitForSync(this.strReplySignal, nTimeout);
  211. ResetSync(this.strReplySignal);
  212. }
  213. return msg.nReplied;
  214. }
  215. function QueueReplyMessage(msg)
  216. {
  217. try
  218. {
  219. msg.nReplied = true;
  220. this.SignalOtherThread(this.strReplySignal);
  221. }
  222. catch(ex)
  223. {
  224. LogMsg("(QueueReplyMessage) Oher side of Queue('" + this.strName + "') has been destroyed: " + ex);
  225. }
  226. }
  227. // Simple wrapper function to allow any remote thread to signal
  228. // this thread. Necessary for cross machine signalling.
  229. function QueueSignalThreadSync(Name)
  230. {
  231. SignalThreadSync(Name);
  232. }