THREADS.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:12k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /******************************************************************************
  2. *       This is a part of the Microsoft Source Code Samples.
  3. *       Copyright (C) 1992-1997 Microsoft Corporation.
  4. *       All rights reserved. 
  5. *       This source code is only intended as a supplement to 
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the 
  8. *       Microsoft samples programs.
  9. ******************************************************************************/
  10. //+---------------------------------------------------------------------------
  11. //
  12. //  File:       pop3.c
  13. //
  14. //  Contents:
  15. //
  16. //  Classes:
  17. //
  18. //  Functions:
  19. //
  20. //----------------------------------------------------------------------------
  21. #include "pop3srvp.h"
  22. #pragma hdrstop
  23. extern BOOL bServiceTerminating;
  24. DWORD
  25. WINAPI
  26. WorkerThread (
  27.     LPVOID WorkContext
  28.     );
  29. HANDLE
  30. InitializeThreads (
  31.     VOID
  32.     )
  33. /*++
  34. Routine Description:
  35.     Starts up the POP3SRV worker threads.  We use two worker threads
  36.     for eachprocessor on the system--this is choosen as a good balance
  37.     that ensures that there are a sufficient number of threads available
  38.     to get useful work done but not too many that context switches
  39.     consume significant overhead.
  40. Arguments:
  41.     None.
  42. Return Value:
  43.     HANDLE - A handle to the completion port if everything was 
  44.         successful, or NULL if there was a failure.  
  45. --*/
  46. {
  47.     SOCKET s;
  48.     DWORD i;
  49.     HANDLE hCompletionPort;
  50.     HANDLE hThreadHandle;
  51.     DWORD dwThreadId;
  52.     SYSTEM_INFO systemInfo;
  53.     //
  54.     // First open a temporary socket that we will use to create the
  55.     // completion port.  In NT 3.51 it will not be necessary to specify
  56.     // the FileHandle parameter of CreateIoCompletionPort()--it will
  57.     // be legal to specify FileHandle as NULL.  However, for NT 3.5
  58.     // we need an overlapped file handle.
  59.     //
  60.     s = socket( AF_INET, SOCK_DGRAM, 0 );
  61.     if ( s == INVALID_SOCKET ) {
  62.         return NULL;
  63.     }
  64.     //
  65.     // Create the completion port that will be used by all the worker
  66.     // threads.
  67.     //
  68.     hCompletionPort = CreateIoCompletionPort( (HANDLE)s, NULL, 0, 0 );
  69.     if ( hCompletionPort == NULL ) {
  70.         closesocket( s );
  71.         return NULL;
  72.     }
  73.     //
  74.     // Close the socket, we don't need it any longer.
  75.     //
  76.     closesocket( s );
  77.     //
  78.     // Determine how many processors are on the system.
  79.     //
  80.     GetSystemInfo( &systemInfo );
  81.     //
  82.     // Create worker threads that will service the actual overlapped
  83.     // I/O requests.  Create two worker threads for each processor
  84.     // on the system.
  85.     //
  86.     for ( i = 0; i < systemInfo.dwNumberOfProcessors*2; i++ ) {
  87.         hThreadHandle = CreateThread(
  88.                             NULL,
  89.                             0,
  90.                             WorkerThread,
  91.                             hCompletionPort,
  92.                             0,
  93.                             &dwThreadId
  94.                             );
  95.         if ( hThreadHandle == NULL ) {
  96.             CloseHandle( hCompletionPort );
  97.             return NULL;
  98.         }
  99.         //
  100.         // Close each thread handle as we open them.  We do not need
  101.         // the thread handles.  Note that each thread will continue
  102.         // executing.
  103.         //
  104.         CloseHandle( hThreadHandle );
  105.     }
  106.     //
  107.     // All was successful.
  108.     //
  109.     return hCompletionPort;
  110. } // InitializeThreads
  111. DWORD
  112. WINAPI
  113. WorkerThread (
  114.     LPVOID WorkContext
  115.     )
  116. /*++
  117. Routine Description:
  118.     This is the main worker routine for the POP3SRV worker threads.  
  119.     Worker threads wait on a completion port for I/O to complete.  When 
  120.     it completes, the worker thread processes the I/O, then either pends 
  121.     new I/O or closes the client's connection.  When the service shuts 
  122.     down, other code closes the completion port which causes 
  123.     GetQueuedCompletionStatus() to wake up and the worker thread then 
  124.     exits.  
  125. Arguments:
  126.     WorkContext - the completion port handle that will get I/O completion
  127.         notifications.
  128. Return Value:
  129.     DWORD - status of the thread.
  130. --*/
  131. {
  132.     HANDLE hCompletionPort = WorkContext;
  133.     BOOL bSuccess;
  134.     DWORD dwIoSize;
  135.     LPOVERLAPPED lpOverlapped;
  136.     PCLIENT_CONTEXT lpClientContext;
  137.     Pop3Disposition Disposition;
  138.     HANDLE hFile;
  139.     CHAR * OutputBuffer;
  140.     DWORD OutputBufferLen;
  141.     TRANSMIT_FILE_BUFFERS TranfileBuffers;
  142.     //
  143.     // Loop servicing I/O completions.
  144.     //
  145.     while ( TRUE ) {
  146.         // --- DavidTr: Slide 14(b) ------------------------------------------
  147.         //
  148.         // Get a completed IO request.
  149.         //
  150.         bSuccess = GetQueuedCompletionStatus(
  151.                        hCompletionPort,
  152.                        &dwIoSize,
  153.                        (LPDWORD)&lpClientContext,
  154.                        &lpOverlapped,
  155.                        (DWORD)-1
  156.                        );
  157.         //
  158.         // If the service is terminating, exit this thread.
  159.         //
  160.         if ( bServiceTerminating ) {
  161.             return 0;
  162.         }
  163.         //
  164.         // If the IO failed, close the socket and free context.
  165.         //
  166.         if ( !bSuccess ) {
  167.             CloseClient( lpClientContext, FALSE );
  168.             continue;
  169.         }
  170.         //
  171.         // If the request was a read, process the client request.
  172.         //
  173.         if ( lpClientContext->LastClientIo == ClientIoRead ) {
  174.             //
  175.             // BUGBUG: if this were a real production piece of code,
  176.             // we would check here for an incomplete read.  Because
  177.             // TCP/IP is a stream oriented protocol, it is feasible
  178.             // that we could receive part of a client request.
  179.             // Therefore, we should check for the CRLF that ends a
  180.             // client request.
  181.             //
  182.             //
  183.             // Process the request.  Pop3Dispatch() handles all aspects 
  184.             // of the request and tells us how to respond to the client.  
  185.             //
  186.             Disposition = Pop3Dispatch(
  187.                               lpClientContext->Context,
  188.                               lpClientContext->Buffer,
  189.                               dwIoSize,
  190.                               &hFile,
  191.                               &OutputBuffer,
  192.                               &OutputBufferLen
  193.                               );
  194.             //
  195.             // Act based on the Disposition.
  196.             //
  197.             switch ( Disposition ) {
  198.             case Pop3_Discard:
  199.                 break;
  200.             case Pop3_SendError:
  201.             case Pop3_SendBuffer:
  202.                 // --- DavidTr: Slide 7(a) -----------------------------------
  203.                 //
  204.                 // Set up context information and perform an overlapped 
  205.                 // write on the socket.  
  206.                 //
  207.                 lpClientContext->LastClientIo = ClientIoWrite;
  208.                 lpClientContext->TransmittedBuffer = OutputBuffer;
  209.                 bSuccess = WriteFile(
  210.                                (HANDLE)lpClientContext->Socket,
  211.                                OutputBuffer,
  212.                                OutputBufferLen,
  213.                                &dwIoSize,
  214.                                &lpClientContext->Overlapped
  215.                                );
  216.                 if ( !bSuccess && GetLastError( ) != ERROR_IO_PENDING ) {
  217.                     CloseClient( lpClientContext, FALSE );
  218.                     continue;
  219.                 }
  220.                 //
  221.                 // Continue looping to get completed IO requests--we
  222.                 // do not want to pend another read now.
  223.                 //
  224.                 continue;
  225.             case Pop3_SendFile:
  226.             case Pop3_SendBufferThenFile:
  227.                 //
  228.                 // Determine based on the disposition whether we will
  229.                 // need to send a head or tail buffer.
  230.                 //
  231.                 if ( Disposition == Pop3_SendFile ) {
  232.                     TranfileBuffers.Head = NULL;
  233.                     TranfileBuffers.HeadLength = 0;
  234.                 } else if ( Disposition == Pop3_SendBufferThenFile ) {
  235.                     TranfileBuffers.Head = OutputBuffer;
  236.                     TranfileBuffers.HeadLength = OutputBufferLen;
  237.                 }
  238.                 //
  239.                 // After the file, we're going to send a .CRLF sequence 
  240.                 // so that the client detects EOF.  Note that 
  241.                 // TransmitFile() will send this terminator in the same 
  242.                 // packet as the last chunk of the file, thereby saving 
  243.                 // network traffic.  
  244.                 //
  245.                 TranfileBuffers.Tail = ".rn";
  246.                 TranfileBuffers.TailLength = 3;
  247.                 //
  248.                 // Set up context for the I/O so that we know how to act 
  249.                 // when the I/O completes.  
  250.                 //
  251.                 lpClientContext->LastClientIo = ClientIoTransmitFile;
  252.                 lpClientContext->TransmittedFile = hFile;
  253.                 lpClientContext->TransmittedBuffer = OutputBuffer;
  254.                 // --- DavidTr: Slide 21 ---------------------------------
  255.                 //
  256.                 // Now transmit the file and the data buffers.
  257.                 //
  258.                 bSuccess = TransmitFile(
  259.                                lpClientContext->Socket,
  260.                                hFile,
  261.                                0,
  262.                                0,
  263.                                &lpClientContext->Overlapped,
  264.                                &TranfileBuffers,
  265.                                0
  266.                                );
  267.                 if ( !bSuccess && GetLastError( ) != ERROR_IO_PENDING ) {
  268.                     CloseClient( lpClientContext, FALSE );
  269.                     continue;
  270.                 }
  271.                 //
  272.                 // Continue looping to get completed IO requests--we
  273.                 // do not want to pend another read now.
  274.                 //
  275.                 continue;
  276.             }
  277.         } else if ( lpClientContext->LastClientIo == ClientIoWrite ) {
  278.             //
  279.             // Clean up after the WriteFile().
  280.             //
  281.             LocalFree( lpClientContext->TransmittedBuffer );
  282.         } else if ( lpClientContext->LastClientIo == ClientIoTransmitFile ) {
  283.             //
  284.             // Clean up after the TransmitFile().
  285.             //
  286.             CloseHandle( lpClientContext->TransmittedFile );
  287.             LocalFree( lpClientContext->TransmittedBuffer );
  288.         } 
  289.         // --- DavidTr: Slide 7(b) ---------------------------------------
  290.         //
  291.         // Pend another read request to get the next client request.
  292.         //
  293.         lpClientContext->LastClientIo = ClientIoRead;
  294.         lpClientContext->BytesReadSoFar = 0;
  295.         bSuccess = ReadFile(
  296.                        (HANDLE)lpClientContext->Socket,
  297.                        lpClientContext->Buffer,
  298.                        sizeof(lpClientContext->Buffer),
  299.                        &dwIoSize,
  300.                        &lpClientContext->Overlapped
  301.                        );
  302.         if ( !bSuccess && GetLastError( ) != ERROR_IO_PENDING ) {
  303.             CloseClient( lpClientContext, FALSE );
  304.             continue;
  305.         }
  306.         //
  307.         // Loop around to get another completed IO request.
  308.         //
  309.     }
  310.     return 0;
  311. } // WorkThread