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.

254 lines
8.9 KiB

  1. /****************************************************************************/
  2. // nschdisp.c
  3. //
  4. // Scheduler Display Driver code.
  5. //
  6. // Copyright (C) 1997-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <precmpdd.h>
  9. #define hdrstop
  10. #define TRC_FILE "nschdisp"
  11. #include <adcg.h>
  12. #include <winddi.h>
  13. #include <adcs.h>
  14. #include <nddapi.h>
  15. #include <aschapi.h>
  16. #include <nshmapi.h>
  17. #include <nwdwioct.h>
  18. #include <nbadisp.h>
  19. #include <nprcount.h>
  20. #include <nsbcdisp.h>
  21. #include <ncmdisp.h>
  22. #define DC_INCLUDE_DATA
  23. #include <ndddata.c>
  24. #undef DC_INCLUDE_DATA
  25. #include <nbainl.h>
  26. #include <nsbcinl.h>
  27. /****************************************************************************/
  28. // SCH_InitShm
  29. //
  30. // Alloc-time SHM init.
  31. /****************************************************************************/
  32. void RDPCALL SCH_InitShm(void)
  33. {
  34. DC_BEGIN_FN("SCH_InitShm");
  35. pddShm->sch.baCompressionEst = SCH_BA_INIT_EST;
  36. pddShm->sch.MPPCCompressionEst = SCH_MPPC_INIT_EST;
  37. DC_END_FN();
  38. }
  39. /****************************************************************************/
  40. // SCHEnoughOutputAccumulated
  41. //
  42. // Determine if there's enough output accumulated to make it worth sending
  43. // to the WD.
  44. /****************************************************************************/
  45. __inline BOOL RDPCALL SCHEnoughOutputAccumulated(void)
  46. {
  47. BOOL rc = FALSE;
  48. UINT32 EstimatedTotal;
  49. DC_BEGIN_FN("SCHEnoughOutputAccumulated");
  50. // We want to flush through to the WD if any of the following are true.
  51. // - new cursor shape (helps snappy feel)
  52. // - the estimated compressed size of the pending orders will fit into
  53. // a large order buffer (estimated to 7/8 of buffer size to increase
  54. // the chances of really fitting into the buffer after running through
  55. // jittery compression algorithms).
  56. EstimatedTotal =
  57. pddShm->oa.TotalOrderBytes +
  58. (BA_GetTotalBounds() * pddShm->sch.baCompressionEst /
  59. SCH_UNCOMP_BYTES) +
  60. (pddShm->pm.paletteChanged *
  61. (UINT32)FIELDOFFSET(TS_UPDATE_PALETTE_PDU, data.palette[0]) +
  62. (PM_NUM_8BPP_PAL_ENTRIES * sizeof(TS_COLOR)));
  63. // If we're using the MPPC compressor, take into account the predicted
  64. // compression ratio.
  65. if (pddShm->sch.schSlowLink)
  66. EstimatedTotal = EstimatedTotal * pddShm->sch.MPPCCompressionEst /
  67. SCH_UNCOMP_BYTES;
  68. if (EstimatedTotal >= (pddShm->sch.LargePackingSize * 7 / 8)) {
  69. INC_INCOUNTER(IN_SCH_OUTPUT);
  70. TRC_NRM((TB,"Enough output bytes - %u", EstimatedTotal));
  71. rc = TRUE;
  72. }
  73. else if (CM_DDGetCursorStamp() != ddLastSentCursorStamp) {
  74. // If we're not shadowing, we optimize to only flush due to
  75. // cursor-shape-change when user input happened recently.
  76. if (NULL != pddShm->pShadowInfo ||
  77. ddSchInputKickMode)
  78. {
  79. INC_INCOUNTER(IN_SCH_NEW_CURSOR);
  80. TRC_NRM((TB,"Changed cursor"));
  81. rc = TRUE;
  82. }
  83. else
  84. {
  85. TRC_NRM((TB,"Avoided changing cursor; not in InputKickMode"));
  86. }
  87. }
  88. DC_END_FN();
  89. return rc;
  90. }
  91. /****************************************************************************/
  92. // SCH_DDOutputAvailable
  93. //
  94. // Called to decide whether to send output to the WD.
  95. /****************************************************************************/
  96. NTSTATUS RDPCALL SCH_DDOutputAvailable(PDD_PDEV ppdev, BOOL mustSend)
  97. {
  98. NTSTATUS status;
  99. TSHARE_DD_OUTPUT_IN outputIn;
  100. TSHARE_DD_OUTPUT_OUT outputOut;
  101. ULONG bytesReturned;
  102. BOOL IoctlNow, schedOnly;
  103. DC_BEGIN_FN("SCH_DDOutputAvailable");
  104. INC_INCOUNTER(IN_SCH_OUT_ALL);
  105. ADD_INCOUNTER(IN_SCH_MUSTSEND, mustSend);
  106. TRC_DBG((TB, "Orders %d, mustSend? %s, scheduler mode %s (%d), %s",
  107. pddShm->oa.TotalOrderBytes,
  108. (mustSend ? "TRUE" : "FALSE"),
  109. ddSchCurrentMode == SCH_MODE_ASLEEP ? "Asleep" :
  110. ddSchCurrentMode == SCH_MODE_NORMAL ? "Normal" :
  111. ddSchCurrentMode == SCH_MODE_TURBO ? "Turbo" : "Unknown",
  112. ddSchCurrentMode,
  113. pddShm->sch.schSlowLink ? "slow link" : "fast link"));
  114. // This routine contains part of the key scheduling algorithm.
  115. // The intent is to IOCTL to the WD if any of the following are true:
  116. // - we have been told that we must send pending data immediately
  117. // - there is enough output to make it worthwhile
  118. // - the current SCH state is ASLEEP
  119. // If the scheduler is ASLEEP and it's a slow link, then we wake the
  120. // scheduler up but we don't do an actual send for performance reasons.
  121. if (mustSend || SCHEnoughOutputAccumulated()) {
  122. IoctlNow = TRUE;
  123. schedOnly = FALSE;
  124. TRC_DBG((TB, "Send data 'cos enough"));
  125. }
  126. else if (ddSchCurrentMode == SCH_MODE_ASLEEP) {
  127. INC_INCOUNTER(IN_SCH_ASLEEP);
  128. IoctlNow = TRUE;
  129. schedOnly = pddShm->sch.schSlowLink;
  130. TRC_DBG((TB, "Send data 'cos asleep: sched only: %d", schedOnly));
  131. }
  132. else {
  133. IoctlNow = FALSE;
  134. schedOnly = FALSE;
  135. }
  136. // If we have decided to send something, do so now. Most often we have
  137. // nothing to do.
  138. if (!IoctlNow) {
  139. INC_INCOUNTER(IN_SCH_DO_NOTHING);
  140. status = STATUS_SUCCESS;
  141. }
  142. else {
  143. outputIn.forceSend = mustSend;
  144. outputIn.pFrameBuf = ppdev->pFrameBuf;
  145. outputIn.frameBufWidth = ddFrameBufX;
  146. outputIn.frameBufHeight = ddFrameBufY;
  147. outputIn.pShm = pddShm;
  148. outputIn.schedOnly = schedOnly;
  149. // Note the current cursor stamp for future reference.
  150. ddLastSentCursorStamp = CM_DDGetCursorStamp();
  151. TRC_DBG((TB, "Send IOCtl to WD, bounds %d, orders %d, mustSend? %s",
  152. BA_GetTotalBounds(), pddShm->oa.TotalOrderBytes,
  153. (mustSend)? "TRUE":"FALSE"));
  154. // If we are not shadowing, then all output will be completely flushed
  155. // on this call.
  156. if (pddShm->pShadowInfo == NULL) {
  157. status = EngFileIoControl(ddWdHandle,
  158. IOCTL_WDTS_DD_OUTPUT_AVAILABLE,
  159. &outputIn, sizeof(TSHARE_DD_OUTPUT_IN),
  160. &outputOut, sizeof(TSHARE_DD_OUTPUT_OUT),
  161. &bytesReturned);
  162. }
  163. // else we are shadowing and may require multiple flush calls
  164. else {
  165. #ifdef DC_DEBUG
  166. unsigned NumRepetitions = 0;
  167. #endif
  168. do {
  169. TRC_DBG((TB, "Send IOCtl to WD, bounds %d, orders %d, mustSend? %s",
  170. BA_GetTotalBounds(), pddShm->oa.TotalOrderBytes,
  171. (mustSend)? "TRUE":"FALSE"));
  172. // The primary stack will update this to indicate how many bytes
  173. // were copied into the shadow data buffer. This will subsequently
  174. // be used by the shadow stack(s) to send the data to its client.
  175. pddShm->pShadowInfo->messageSize = 0;
  176. #ifdef DC_HICOLOR
  177. pddShm->pShadowInfo->messageSizeEx = 0;
  178. #endif
  179. status = EngFileIoControl(ddWdHandle,
  180. IOCTL_WDTS_DD_OUTPUT_AVAILABLE,
  181. &outputIn, sizeof(TSHARE_DD_OUTPUT_IN),
  182. &outputOut, sizeof(TSHARE_DD_OUTPUT_OUT),
  183. &bytesReturned);
  184. pddShm->pShadowInfo->messageSize = 0;
  185. #ifdef DC_HICOLOR
  186. pddShm->pShadowInfo->messageSizeEx = 0;
  187. #endif
  188. #ifdef DC_DEBUG
  189. // If we have a locked-up shadow session looping in sending
  190. // output, break out. We should only have to call to the
  191. // WD a few times, so make the check 250 to be safe.
  192. NumRepetitions++;
  193. if (NumRepetitions == 250) {
  194. TRC_ASSERT((NumRepetitions != 250),
  195. (TB,"We seem to be in an infinite output loop "
  196. "on shadow output flushing; TotalOrders=%u, "
  197. "TotalBounds=%u", pddShm->oa.TotalOrderBytes,
  198. pddShm->ba.totalArea));
  199. }
  200. #endif
  201. } while ((pddShm->oa.TotalOrderBytes || BA_GetTotalBounds()) &&
  202. (status == STATUS_SUCCESS) && !schedOnly);
  203. }
  204. // Update the new scheduler mode.
  205. ddSchCurrentMode = outputOut.schCurrentMode;
  206. ddSchInputKickMode = outputOut.schInputKickMode;
  207. TRC_DBG((TB, "New Scheduler mode is %s (%d)",
  208. ddSchCurrentMode == SCH_MODE_ASLEEP ? "Asleep" :
  209. ddSchCurrentMode == SCH_MODE_NORMAL ? "Normal" :
  210. ddSchCurrentMode == SCH_MODE_TURBO ? "Turbo" : "Unknown",
  211. ddSchCurrentMode));
  212. }
  213. DC_END_FN();
  214. return status;
  215. }