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.

391 lines
10 KiB

  1. /*++
  2. Copyright (c) 1994 - 1995 Microsoft Corporation
  3. Module Name:
  4. sizethrd.c
  5. Abstract:
  6. The NT server share for downlevel jobs does not set the size whilst
  7. spooling. The SizeDetectionThread periodically wakes walks all the
  8. actively spooling jobs and if necessary updates the size.
  9. Author:
  10. Matthew Felton (mattfe) May 1994
  11. Revision History:
  12. --*/
  13. #include <precomp.h>
  14. #include "filepool.hxx"
  15. #define SIZE_THREAD_WAIT_PERIOD 2.5*1000 // period size thread sleeps
  16. // for polling file sizes
  17. BOOL gbSizeDetectionRunning = FALSE;
  18. BOOL gbRequestSizeDetection = FALSE;
  19. VOID
  20. SizeDetectionThread(
  21. PVOID pv
  22. );
  23. VOID
  24. SizeDetectionOnSpooler(
  25. PINISPOOLER pIniSpooler
  26. );
  27. VOID
  28. CheckSizeDetectionThread(
  29. VOID
  30. )
  31. /*++
  32. Routine Description:
  33. Check if the size detection thread is running. If it isn't, then
  34. start a new one up.
  35. Note: there is exactly one size detection thread in the system that
  36. runs through all spoolers.
  37. Arguments:
  38. Return Value:
  39. --*/
  40. {
  41. DWORD ThreadId;
  42. HANDLE hThread;
  43. SplInSem();
  44. gbRequestSizeDetection = TRUE;
  45. //
  46. // If the thread isn't running, start it. Otherwise request
  47. // that it starts.
  48. //
  49. if( !gbSizeDetectionRunning ){
  50. hThread = CreateThread( NULL,
  51. 0,
  52. (LPTHREAD_START_ROUTINE)SizeDetectionThread,
  53. pLocalIniSpooler,
  54. 0,
  55. &ThreadId );
  56. if( hThread ){
  57. gbSizeDetectionRunning = TRUE;
  58. CloseHandle( hThread );
  59. }
  60. }
  61. }
  62. VOID
  63. SizeDetectionThread(
  64. PVOID pv
  65. )
  66. /*++
  67. Routine Description:
  68. Walk through all spoolers and printers to see if there are any
  69. jobs that have been added via AddJob. Then see if their size
  70. has changed.
  71. Arguments:
  72. PVOID - unused.
  73. Return Value:
  74. --*/
  75. {
  76. PINISPOOLER pIniSpooler;
  77. PINISPOOLER pIniNextSpooler;
  78. EnterSplSem();
  79. while( gbRequestSizeDetection ){
  80. //
  81. // Turn it off since we are at the very beginning of the
  82. // loop and we check all pIniSpoolers.
  83. //
  84. gbRequestSizeDetection = FALSE;
  85. if( pLocalIniSpooler ){
  86. INCSPOOLERREF( pLocalIniSpooler );
  87. }
  88. //
  89. // Walk through all spoolers.
  90. //
  91. for( pIniSpooler = pLocalIniSpooler;
  92. pIniSpooler;
  93. pIniSpooler = pIniNextSpooler ){
  94. //
  95. // If this spooler prints, check it.
  96. //
  97. if( pIniSpooler->SpoolerFlags & SPL_PRINT ){
  98. //
  99. // This will leave the critical section.
  100. // gbRequestSizeDetection will be turned on if this printer
  101. // has a spooling job.
  102. //
  103. SizeDetectionOnSpooler( pIniSpooler );
  104. }
  105. //
  106. // Save the next spooler then decrement the refcount
  107. // on the current one. We must do it in this order because
  108. // as soon as we release the refcount, it may disappear.
  109. //
  110. // We must protect the next spooler immediately since
  111. // during the DecSpoolerRef( pIniSpooler ), it might
  112. // get deleted.
  113. //
  114. pIniNextSpooler = pIniSpooler->pIniNextSpooler;
  115. if( pIniNextSpooler ){
  116. INCSPOOLERREF( pIniNextSpooler );
  117. }
  118. DECSPOOLERREF( pIniSpooler );
  119. }
  120. LeaveSplSem();
  121. Sleep( (DWORD)SIZE_THREAD_WAIT_PERIOD );
  122. EnterSplSem();
  123. }
  124. gbSizeDetectionRunning = FALSE;
  125. LeaveSplSem();
  126. ExitThread( 0 );
  127. }
  128. VOID
  129. SizeDetectionOnSpooler(
  130. IN PINISPOOLER pIniSpooler
  131. )
  132. /*++
  133. Routine Description:
  134. Detect if a spooler has a printing job.
  135. Arguments:
  136. pIniSpooler - Spooler to check.
  137. Return Value:
  138. --*/
  139. {
  140. PINIPRINTER pIniPrinter;
  141. PINIPRINTER pIniNextPrinter;
  142. PINIJOB pIniJob, pIniNextJob, pChainedJob;
  143. DWORD dwPosition, dwChainedJobSize;
  144. //
  145. // Loop through all printers on this spooler.
  146. //
  147. for( pIniPrinter = pIniSpooler->pIniPrinter;
  148. pIniPrinter;
  149. pIniPrinter = pIniNextPrinter ){
  150. INCPRINTERREF(pIniPrinter);
  151. //
  152. // Loop through all jobs on this printer.
  153. //
  154. for( pIniJob = pIniPrinter->pIniFirstJob;
  155. pIniJob;
  156. pIniJob = pIniNextJob ){
  157. SPLASSERT( pIniJob->signature == IJ_SIGNATURE );
  158. SPLASSERT( pIniPrinter->signature == IP_SIGNATURE );
  159. INCJOBREF(pIniJob);
  160. SplInSem();
  161. if ( (pIniJob->Status & JOB_SPOOLING) &&
  162. (pIniJob->Status & JOB_TYPE_ADDJOB) ) {
  163. WCHAR szFileName[MAX_PATH];
  164. HANDLE hFile = INVALID_HANDLE_VALUE;
  165. DWORD dwFileSize = 0;
  166. BOOL DoClose = TRUE;
  167. gbRequestSizeDetection = TRUE;
  168. if ( pIniJob->hFileItem != INVALID_HANDLE_VALUE )
  169. {
  170. hFile = GetCurrentWriter(pIniJob->hFileItem, TRUE);
  171. if ( hFile == INVALID_HANDLE_VALUE )
  172. {
  173. StringCchCopy(szFileName, COUNTOF(szFileName), pIniJob->pszSplFileName);
  174. }
  175. else
  176. {
  177. DoClose = FALSE;
  178. }
  179. }
  180. else
  181. {
  182. GetFullNameFromId (pIniPrinter,
  183. pIniJob->JobId,
  184. TRUE,
  185. szFileName,
  186. COUNTOF(szFileName),
  187. FALSE);
  188. }
  189. LeaveSplSem();
  190. SplOutSem();
  191. if ( hFile == INVALID_HANDLE_VALUE )
  192. {
  193. hFile = CreateFile(szFileName,
  194. 0,
  195. FILE_SHARE_WRITE, NULL,
  196. OPEN_EXISTING,
  197. FILE_FLAG_SEQUENTIAL_SCAN,
  198. 0);
  199. }
  200. if ( hFile != INVALID_HANDLE_VALUE ) {
  201. SeekPrinterSetEvent(pIniJob, hFile, FALSE);
  202. dwFileSize = GetFileSize( hFile, 0 );
  203. if ( DoClose )
  204. {
  205. CloseHandle( hFile );
  206. }
  207. }
  208. EnterSplSem();
  209. SplInSem();
  210. SPLASSERT( pIniJob->signature == IJ_SIGNATURE );
  211. //
  212. // Chained job size include all the jobs in the chain
  213. // But since the next jobs size field will have the size
  214. // of all subsequent jobs we do not need to walk thru the
  215. // whole chain
  216. //
  217. dwChainedJobSize = 0;
  218. if ( pIniJob->NextJobId ) {
  219. if ( pChainedJob = FindJob(pIniPrinter,
  220. pIniJob->NextJobId,
  221. &dwPosition) )
  222. dwChainedJobSize = pChainedJob->Size;
  223. else
  224. SPLASSERT(pChainedJob != NULL);
  225. }
  226. if ( pIniJob->Size < dwFileSize + dwChainedJobSize ) {
  227. DWORD dwOldSize = pIniJob->Size;
  228. DWORD dwOldValidSize = pIniJob->dwValidSize;
  229. //
  230. // Fix for print while spooling (AddJob/ScheduleJob)
  231. //
  232. // The file size has changed. At this time we only
  233. // know that the file is extended, not that the extended
  234. // range has valid data (there's a small window where the
  235. // extended window has not been filled with data).
  236. //
  237. // This does guarantee that the _previous_ extension
  238. // has been written, however.
  239. //
  240. pIniJob->dwValidSize = dwOldSize;
  241. pIniJob->Size = dwFileSize + dwChainedJobSize;
  242. //
  243. // Wait until Jobs reach our size threshold before
  244. // we schedule them.
  245. //
  246. if (( dwOldValidSize < dwFastPrintSlowDownThreshold ) &&
  247. ( dwOldSize >= dwFastPrintSlowDownThreshold ) &&
  248. ( pIniJob->WaitForWrite == NULL )) {
  249. CHECK_SCHEDULER();
  250. }
  251. SetPrinterChange(pIniPrinter,
  252. pIniJob,
  253. NVSpoolJob,
  254. PRINTER_CHANGE_WRITE_JOB,
  255. pIniPrinter->pIniSpooler);
  256. // Support for despooling whilst spooling
  257. // for Down Level jobs
  258. if (pIniJob->WaitForWrite != NULL)
  259. SetEvent( pIniJob->WaitForWrite );
  260. }
  261. }
  262. pIniNextJob = pIniJob->pIniNextJob;
  263. //
  264. // We must protect pIniNextJob immediately,
  265. // since we will may leave critical section in
  266. // DeleteJobCheck (it may call DeleteJob). While out
  267. // of critical section, pIniNextJob may be deleted,
  268. // causing it's next pointer to be bogus. We'll AV
  269. // after we try and process it.
  270. //
  271. if (pIniNextJob) {
  272. INCJOBREF(pIniNextJob);
  273. }
  274. DECJOBREF(pIniJob);
  275. DeleteJobCheck(pIniJob);
  276. if (pIniNextJob) {
  277. DECJOBREF(pIniNextJob);
  278. }
  279. }
  280. pIniNextPrinter = pIniPrinter->pNext;
  281. if( pIniNextPrinter ){
  282. INCPRINTERREF( pIniNextPrinter );
  283. }
  284. DECPRINTERREF(pIniPrinter);
  285. if( pIniNextPrinter ){
  286. DECPRINTERREF( pIniNextPrinter );
  287. }
  288. }
  289. SplInSem();
  290. }