ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

state.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         GPL - See COPYING in the top level directory
00004  * FILE:            ntoskrnl/ps/state.c
00005  * PURPOSE:         Process Manager: Process/Thread State Control
00006  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007  *                  Thomas Weidenmueller (w3seek@reactos.org)
00008  */
00009 
00010 /* INCLUDES ******************************************************************/
00011 
00012 #include <ntoskrnl.h>
00013 #define NDEBUG
00014 #include <debug.h>
00015 
00016 /* PRIVATE FUNCTIONS *********************************************************/
00017 
00018 VOID
00019 NTAPI
00020 PspQueueApcSpecialApc(IN PKAPC Apc,
00021                       IN OUT PKNORMAL_ROUTINE* NormalRoutine,
00022                       IN OUT PVOID* NormalContext,
00023                       IN OUT PVOID* SystemArgument1,
00024                       IN OUT PVOID* SystemArgument2)
00025 {
00026     /* Free the APC and do nothing else */
00027     ExFreePool(Apc);
00028 }
00029 
00030 NTSTATUS
00031 NTAPI
00032 PsResumeThread(IN PETHREAD Thread,
00033                OUT PULONG PreviousCount OPTIONAL)
00034 {
00035     ULONG OldCount;
00036     PAGED_CODE();
00037 
00038     /* Resume the thread */
00039     OldCount = KeResumeThread(&Thread->Tcb);
00040 
00041     /* Return the count if asked */
00042     if (PreviousCount) *PreviousCount = OldCount;
00043     return STATUS_SUCCESS;
00044 }
00045 
00046 NTSTATUS
00047 NTAPI
00048 PsSuspendThread(IN PETHREAD Thread,
00049                 OUT PULONG PreviousCount OPTIONAL)
00050 {
00051     NTSTATUS Status;
00052     ULONG OldCount = 0;
00053     PAGED_CODE();
00054 
00055     /* Guard with SEH because KeSuspendThread can raise an exception */
00056     _SEH2_TRY
00057     {
00058         /* Check if we're suspending ourselves */
00059         if (Thread == PsGetCurrentThread())
00060         {
00061             /* Do the suspend */
00062             OldCount = KeSuspendThread(&Thread->Tcb);
00063 
00064             /* We are done */
00065             Status = STATUS_SUCCESS;
00066         }
00067         else
00068         {
00069             /* Acquire rundown */
00070             if (ExAcquireRundownProtection(&Thread->RundownProtect))
00071             {
00072                 /* Make sure the thread isn't terminating */
00073                 if (Thread->Terminated)
00074                 {
00075                     /* Fail */
00076                     Status = STATUS_THREAD_IS_TERMINATING;
00077                 }
00078                 else
00079                 {
00080                     /* Otherwise, do the suspend */
00081                     OldCount = KeSuspendThread(&Thread->Tcb);
00082 
00083                     /* Check if it terminated during the suspend */
00084                     if (Thread->Terminated)
00085                     {
00086                         /* Wake it back up and fail */
00087                         KeForceResumeThread(&Thread->Tcb);
00088                         Status = STATUS_THREAD_IS_TERMINATING;
00089                         OldCount = 0;
00090                     }
00091                 }
00092 
00093                 /* Release rundown protection */
00094                 ExReleaseRundownProtection(&Thread->RundownProtect);
00095 
00096                 /* We are done */
00097                 Status = STATUS_SUCCESS;
00098             }
00099             else
00100             {
00101                 /* Thread is terminating */
00102                 Status = STATUS_THREAD_IS_TERMINATING;
00103             }
00104         }
00105     }
00106     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00107     {
00108         /* Get the exception code */
00109         Status = _SEH2_GetExceptionCode();
00110 
00111         /* Don't fail if we merely couldn't write the handle back */
00112         if (Status != STATUS_SUSPEND_COUNT_EXCEEDED) Status = STATUS_SUCCESS;
00113     }
00114     _SEH2_END;
00115 
00116     /* Write back the previous count */
00117     if (PreviousCount) *PreviousCount = OldCount;
00118     return Status;
00119 }
00120 
00121 NTSTATUS
00122 NTAPI
00123 PsResumeProcess(IN PEPROCESS Process)
00124 {
00125     PETHREAD Thread;
00126     PAGED_CODE();
00127 
00128     /* Lock the Process */
00129     if (!ExAcquireRundownProtection(&Process->RundownProtect))
00130     {
00131         /* Process is terminating */
00132         return STATUS_PROCESS_IS_TERMINATING;
00133     }
00134 
00135     /* Get the first thread */
00136     Thread = PsGetNextProcessThread(Process, NULL);
00137     while (Thread)
00138     {
00139         /* Resume it */
00140         KeResumeThread(&Thread->Tcb);
00141 
00142         /* Move to the next thread */
00143         Thread = PsGetNextProcessThread(Process, Thread);
00144     }
00145 
00146     /* Unlock the process */
00147     ExReleaseRundownProtection(&Process->RundownProtect);
00148     return STATUS_SUCCESS;
00149 }
00150 
00151 NTSTATUS
00152 NTAPI
00153 PsSuspendProcess(IN PEPROCESS Process)
00154 {
00155     PETHREAD Thread;
00156     PAGED_CODE();
00157 
00158     /* Lock the Process */
00159     if (!ExAcquireRundownProtection(&Process->RundownProtect))
00160     {
00161         /* Process is terminating */
00162         return STATUS_PROCESS_IS_TERMINATING;
00163     }
00164 
00165     /* Get the first thread */
00166     Thread = PsGetNextProcessThread(Process, NULL);
00167     while (Thread)
00168     {
00169         /* Resume it */
00170         PsSuspendThread(Thread, NULL);
00171 
00172         /* Move to the next thread */
00173         Thread = PsGetNextProcessThread(Process, Thread);
00174     }
00175 
00176     /* Unlock the process */
00177     ExReleaseRundownProtection(&Process->RundownProtect);
00178     return STATUS_SUCCESS;
00179 }
00180 
00181 /* PUBLIC FUNCTIONS **********************************************************/
00182 
00183 /*
00184  * @implemented
00185  */
00186 NTSTATUS
00187 NTAPI
00188 NtAlertThread(IN HANDLE ThreadHandle)
00189 {
00190     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00191     PETHREAD Thread;
00192     NTSTATUS Status;
00193 
00194     /* Reference the Object */
00195     Status = ObReferenceObjectByHandle(ThreadHandle,
00196                                        THREAD_SUSPEND_RESUME,
00197                                        PsThreadType,
00198                                        PreviousMode,
00199                                        (PVOID*)&Thread,
00200                                        NULL);
00201     if (NT_SUCCESS(Status))
00202     {
00203         /*
00204          * Do an alert depending on the processor mode. If some kmode code wants to
00205          * enforce a umode alert it should call KeAlertThread() directly. If kmode
00206          * code wants to do a kmode alert it's sufficient to call it with Zw or just
00207          * use KeAlertThread() directly
00208          */
00209         KeAlertThread(&Thread->Tcb, PreviousMode);
00210 
00211         /* Dereference Object */
00212         ObDereferenceObject(Thread);
00213     }
00214 
00215     /* Return status */
00216     return Status;
00217 }
00218 
00219 NTSTATUS
00220 NTAPI
00221 NtAlertResumeThread(IN HANDLE ThreadHandle,
00222                     OUT PULONG SuspendCount)
00223 {
00224     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00225     PETHREAD Thread;
00226     NTSTATUS Status;
00227     ULONG PreviousState;
00228 
00229     /* Check if we came from user mode with a suspend count */
00230     if ((SuspendCount) && (PreviousMode != KernelMode))
00231     {
00232         /* Enter SEH for probing */
00233         _SEH2_TRY
00234         {
00235             /* Probe the count */
00236             ProbeForWriteUlong(SuspendCount);
00237         }
00238         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00239         {
00240             /* Return the exception code */
00241             _SEH2_YIELD(return _SEH2_GetExceptionCode());
00242         }
00243         _SEH2_END;
00244     }
00245 
00246     /* Reference the Object */
00247     Status = ObReferenceObjectByHandle(ThreadHandle,
00248                                        THREAD_SUSPEND_RESUME,
00249                                        PsThreadType,
00250                                        PreviousMode,
00251                                        (PVOID*)&Thread,
00252                                        NULL);
00253     if (NT_SUCCESS(Status))
00254     {
00255         /* Call the Kernel Function */
00256         PreviousState = KeAlertResumeThread(&Thread->Tcb);
00257 
00258         /* Dereference Object */
00259         ObDereferenceObject(Thread);
00260 
00261         /* Check if the caller gave a suspend count */
00262         if (SuspendCount)
00263         {
00264             /* Enter SEH for write */
00265             _SEH2_TRY
00266             {
00267                 /* Write state back */
00268                 *SuspendCount = PreviousState;
00269             }
00270             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00271             {
00272                 /* Get exception code */
00273                 Status = _SEH2_GetExceptionCode();
00274             }
00275             _SEH2_END;
00276         }
00277     }
00278 
00279     /* Return status */
00280     return Status;
00281 }
00282 
00283 NTSTATUS
00284 NTAPI
00285 NtResumeThread(IN HANDLE ThreadHandle,
00286                OUT PULONG SuspendCount OPTIONAL)
00287 {
00288     PETHREAD Thread;
00289     ULONG Prev;
00290     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00291     NTSTATUS Status;
00292     PAGED_CODE();
00293 
00294     /* Check if caller gave a suspend count from user mode */
00295     if ((SuspendCount) && (PreviousMode != KernelMode))
00296     {
00297         /* Enter SEH for probing */
00298         _SEH2_TRY
00299         {
00300             /* Probe the count */
00301             ProbeForWriteUlong(SuspendCount);
00302         }
00303         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00304         {
00305             /* Return the exception code */
00306             _SEH2_YIELD(return _SEH2_GetExceptionCode());
00307         }
00308         _SEH2_END;
00309     }
00310 
00311     /* Get the Thread Object */
00312     Status = ObReferenceObjectByHandle(ThreadHandle,
00313                                        THREAD_SUSPEND_RESUME,
00314                                        PsThreadType,
00315                                        PreviousMode,
00316                                        (PVOID*)&Thread,
00317                                        NULL);
00318     if (!NT_SUCCESS(Status)) return Status;
00319 
00320     /* Call the internal function */
00321     Status = PsResumeThread(Thread, &Prev);
00322 
00323     /* Check if the caller wanted the count back */
00324     if (SuspendCount)
00325     {
00326         /* Enter SEH for write back */
00327         _SEH2_TRY
00328         {
00329             /* Write the count */
00330             *SuspendCount = Prev;
00331         }
00332         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00333         {
00334             /* Get the exception code */
00335             Status = _SEH2_GetExceptionCode();
00336         }
00337         _SEH2_END;
00338     }
00339 
00340     /* Dereference and return */
00341     ObDereferenceObject(Thread);
00342     return Status;
00343 }
00344 
00345 NTSTATUS
00346 NTAPI
00347 NtSuspendThread(IN HANDLE ThreadHandle,
00348                 OUT PULONG PreviousSuspendCount OPTIONAL)
00349 {
00350     PETHREAD Thread;
00351     ULONG Prev;
00352     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00353     NTSTATUS Status;
00354     PAGED_CODE();
00355 
00356     /* Check if caller gave a suspend count from user mode */
00357     if ((PreviousSuspendCount) && (PreviousMode != KernelMode))
00358     {
00359         /* Enter SEH for probing */
00360         _SEH2_TRY
00361         {
00362             /* Probe the count */
00363             ProbeForWriteUlong(PreviousSuspendCount);
00364         }
00365         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00366         {
00367             /* Return the exception code */
00368             _SEH2_YIELD(return _SEH2_GetExceptionCode());
00369         }
00370         _SEH2_END;
00371     }
00372 
00373     /* Get the Thread Object */
00374     Status = ObReferenceObjectByHandle(ThreadHandle,
00375                                        THREAD_SUSPEND_RESUME,
00376                                        PsThreadType,
00377                                        PreviousMode,
00378                                        (PVOID*)&Thread,
00379                                        NULL);
00380     if (!NT_SUCCESS(Status)) return Status;
00381 
00382     /* Call the internal function */
00383     Status = PsSuspendThread(Thread, &Prev);
00384     ObDereferenceObject(Thread);
00385     if (!NT_SUCCESS(Status)) return Status;
00386 
00387     /* Protect write with SEH */
00388     _SEH2_TRY
00389     {
00390         /* Return the Previous Count */
00391         if (PreviousSuspendCount) *PreviousSuspendCount = Prev;
00392     }
00393     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00394     {
00395         /* Get the exception code */
00396         Status = _SEH2_GetExceptionCode();
00397     }
00398     _SEH2_END;
00399 
00400     /* Return */
00401     return Status;
00402 }
00403 
00404 NTSTATUS
00405 NTAPI
00406 NtSuspendProcess(IN HANDLE ProcessHandle)
00407 {
00408     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00409     PEPROCESS Process;
00410     NTSTATUS Status;
00411     PAGED_CODE();
00412 
00413     /* Reference the process */
00414     Status = ObReferenceObjectByHandle(ProcessHandle,
00415                                        PROCESS_SUSPEND_RESUME,
00416                                        PsProcessType,
00417                                        PreviousMode,
00418                                        (PVOID*)&Process,
00419                                        NULL);
00420     if (NT_SUCCESS(Status))
00421     {
00422         /* Call the internal function */
00423         Status = PsSuspendProcess(Process);
00424         ObDereferenceObject(Process);
00425     }
00426 
00427     /* Return status */
00428     return Status;
00429 }
00430 
00431 NTSTATUS
00432 NTAPI
00433 NtResumeProcess(IN HANDLE ProcessHandle)
00434 {
00435     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00436     PEPROCESS Process;
00437     NTSTATUS Status;
00438     PAGED_CODE();
00439 
00440     /* Reference the process */
00441     Status = ObReferenceObjectByHandle(ProcessHandle,
00442                                        PROCESS_SUSPEND_RESUME,
00443                                        PsProcessType,
00444                                        PreviousMode,
00445                                        (PVOID*)&Process,
00446                                        NULL);
00447     if (NT_SUCCESS(Status))
00448     {
00449         /* Call the internal function */
00450         Status = PsResumeProcess(Process);
00451         ObDereferenceObject(Process);
00452     }
00453 
00454     /* Return status */
00455     return Status;
00456 }
00457 
00458 NTSTATUS
00459 NTAPI
00460 NtTestAlert(VOID)
00461 {
00462     /* Check and Alert Thread if needed */
00463     return KeTestAlertThread(ExGetPreviousMode()) ?
00464            STATUS_ALERTED : STATUS_SUCCESS;
00465 }
00466 
00467 /*++
00468  * @name NtQueueApcThread
00469  * NT4
00470  *
00471  *    This routine is used to queue an APC from user-mode for the specified
00472  *    thread.
00473  *
00474  * @param ThreadHandle
00475  *        Handle to the Thread.
00476  *        This handle must have THREAD_SET_CONTEXT privileges.
00477  *
00478  * @param ApcRoutine
00479  *        Pointer to the APC Routine to call when the APC executes.
00480  *
00481  * @param NormalContext
00482  *        Pointer to the context to send to the Normal Routine.
00483  *
00484  * @param SystemArgument[1-2]
00485  *        Pointer to a set of two parameters that contain untyped data.
00486  *
00487  * @return STATUS_SUCCESS or failure cute from associated calls.
00488  *
00489  * @remarks The thread must enter an alertable wait before the APC will be
00490  *          delivered.
00491  *
00492  *--*/
00493 NTSTATUS
00494 NTAPI
00495 NtQueueApcThread(IN HANDLE ThreadHandle,
00496                  IN PKNORMAL_ROUTINE ApcRoutine,
00497                  IN PVOID NormalContext,
00498                  IN PVOID SystemArgument1,
00499                  IN PVOID SystemArgument2)
00500 {
00501     PKAPC Apc;
00502     PETHREAD Thread;
00503     NTSTATUS Status = STATUS_SUCCESS;
00504     PAGED_CODE();
00505 
00506     /* Get ETHREAD from Handle */
00507     Status = ObReferenceObjectByHandle(ThreadHandle,
00508                                        THREAD_SET_CONTEXT,
00509                                        PsThreadType,
00510                                        ExGetPreviousMode(),
00511                                        (PVOID)&Thread,
00512                                        NULL);
00513     if (!NT_SUCCESS(Status)) return Status;
00514 
00515     /* Check if this is a System Thread */
00516     if (Thread->SystemThread)
00517     {
00518         /* Fail */
00519         Status = STATUS_INVALID_HANDLE;
00520         goto Quit;
00521     }
00522 
00523     /* Allocate an APC */
00524     Apc = ExAllocatePoolWithTag(NonPagedPool |
00525                                 POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
00526                                 sizeof(KAPC),
00527                                 TAG_PS_APC);
00528     if (!Apc)
00529     {
00530         /* Fail */
00531         Status = STATUS_NO_MEMORY;
00532         goto Quit;
00533     }
00534 
00535     /* Initialize the APC */
00536     KeInitializeApc(Apc,
00537                     &Thread->Tcb,
00538                     OriginalApcEnvironment,
00539                     PspQueueApcSpecialApc,
00540                     NULL,
00541                     ApcRoutine,
00542                     UserMode,
00543                     NormalContext);
00544 
00545     /* Queue it */
00546     if (!KeInsertQueueApc(Apc,
00547                           SystemArgument1,
00548                           SystemArgument2,
00549                           IO_NO_INCREMENT))
00550     {
00551         /* We failed, free it */
00552         ExFreePool(Apc);
00553         Status = STATUS_UNSUCCESSFUL;
00554     }
00555 
00556     /* Dereference Thread and Return */
00557 Quit:
00558     ObDereferenceObject(Thread);
00559     return Status;
00560 }
00561 
00562 /* EOF */

Generated on Sun May 27 2012 04:20:29 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.