Mailing List Archives
Authenticated access
|
|
|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Condor-users] Condor and processor affinity
- Date: Mon, 13 Jul 2009 08:47:38 -0500
- From: Matthew Farrellee <matt@xxxxxxxxxx>
- Subject: Re: [Condor-users] Condor and processor affinity
(added condor-users back, it had been dropped)
This is all good to know. Maybe Matt Hope has some other thoughts on
managing processes on Windows.
Best,
matt
Ben Burnett wrote:
> Yes, we have considered using Windows "Job" objects, but because, as Matt
> pointed out, a process can only be a member of one Windows Job object.
> Thus, if Condor used Job objects, no Condor jobs could use processes that
> used Windows Job objects as the Condor jobs would fail to execute (being
> unable to add themselves to another Windows Job object).
>
> My understanding is that we have also spoken to MS about this in the past,
> and that while they have agreed that nested Job objects, or processes in
> more than one Job would be cool, that there has been little call or
> interest in it. Maybe it is time to try talking to them again, given the
> large rise in multi-core and cpu machines? (Since it seems to be a way to
> manage a group of process on one cpu [or core].)
>
> Assuming child process don't inherit processor affinity, we could easily
> fake the inheritance by receiving callbacks each time a new child process
> is created. If its parent has its processor affinity set, and we
> recognize it (process family code), then set the child's affinity as well.
>
> Regards,
> -B
>
> On Thu, July 9, 2009 3:10 pm, Matthew Farrellee wrote:
>> Todd, Ben,
>>
>> Have you considered such an interface? Does it have the nesting problem
>> of Job objects within Job objects?
>>
>> Best,
>>
>>
>> matt
>>
>> Matt Hope wrote:
>>> As an aside on windows are you using Job objects to control this or
>>> simply setting the Affinity of the first launched process?
>>>
>>> Using job objects sorts the child processes problem but might not play
>>> nicely with peoples usage of this (a process can only be a member of one
>>> job and cannot stop being a member of a job once attached to it) so it
>>> would be nice to know how this is enforced.
>>>
>>> Here's some .Net code to do this yourself (as well as control your
>>> memory) in case anyone else finds it useful
>>> Translating to raw win32 is pretty trivial
>>>
>>> You could extend this on windows to do many of the complex/error prone
>>> things condor currently has to do by hand such as killing all child
>>> processes within a job, determing cpu time of the job as a whole, the
>>> peak memory usage etc...
>>>
>>> using System;
>>> using System.Collections;
>>> using System.Diagnostics;
>>> using System.Runtime.InteropServices;
>>>
>>> namespace JobObjects
>>> {
>>> /// <summary>An interface to the Windows Job Objects API.</summary>
>>> public class Controller
>>> {
>>> #region Native 32/64 Bit Switching Flag
>>> /// <summary>
>>> /// The structures returned by Windows are different sizes depending
>>> on whether
>>> /// the operating system is running in 32bit or 64bit mode.
>>> /// </summary>
>>> private static readonly bool Is32Bit = (IntPtr.Size == 4);
>>> #endregion
>>>
>>> #region JobObjectInfoClass Enumeration
>>> /// <summary>
>>> /// Information class for the limits to be set. This parameter can
>>> be one of
>>> /// the following values.
>>> /// </summary>
>>> private enum JobObjectInfoClass
>>> {
>>> /// <summary>
>>> /// The lpJobObjectInfo parameter is a pointer to a
>>> /// JOBOBJECT_BASIC_ACCOUNTING_INFORMATION structure.
>>> /// </summary>
>>> BasicAccountingInformation = 1,
>>>
>>> /// <summary>
>>> /// The lpJobObjectInfo parameter is a pointer to a
>>> /// JOBOBJECT_BASIC_LIMIT_INFORMATION structure.
>>> /// </summary>
>>> BasicLimitInformation = 2,
>>>
>>> /// <summary>
>>> /// The lpJobObjectInfo parameter is a pointer to a
>>> /// JOBOBJECT_BASIC_PROCESS_ID_LIST structure.
>>> /// </summary>
>>> BasicProcessIdList = 3,
>>>
>>> /// <summary>
>>> /// The lpJobObjectInfo parameter is a pointer to a
>>> /// JOBOBJECT_BASIC_UI_RESTRICTIONS structure.
>>> /// </summary>
>>> BasicUIRestrictions = 4,
>>>
>>> /// <summary>
>>> /// The lpJobObjectInfo parameter is a pointer to a
>>> /// JOBOBJECT_SECURITY_LIMIT_INFORMATION structure.
>>> /// The hJob handle must have the
>>> JOB_OBJECT_SET_SECURITY_ATTRIBUTES
>>> /// access right associated with it.
>>> /// </summary>
>>> SecurityLimitInformation = 5,
>>>
>>> /// <summary>
>>> /// The lpJobObjectInfo parameter is a pointer to a
>>> /// JOBOBJECT_END_OF_JOB_TIME_INFORMATION structure.
>>> /// </summary>
>>> EndOfJobTimeInformation = 6,
>>>
>>> /// <summary>
>>> /// The lpJobObjectInfo parameter is a pointer to a
>>> /// JOBOBJECT_ASSOCIATE_COMPLETION_PORT structure.
>>> /// </summary>
>>> AssociateCompletionPortInformation = 7,
>>>
>>> /// <summary>
>>> /// The lpJobObjectInfo parameter is a pointer to a
>>> /// JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION structure.
>>> /// </summary>
>>> BasicAndIoAccountingInformation = 8,
>>>
>>> /// <summary>
>>> /// The lpJobObjectInfo parameter is a pointer to a
>>> /// JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure.
>>> /// </summary>
>>> ExtendedLimitInformation = 9
>>> }
>>> #endregion
>>>
>>> #region LimitFlags Enumeration
>>> /// <summary>
>>> /// Limit flags that are in effect. This member is a bit field that
>>> determines
>>> /// whether other structure members are used. Any combination of the
>>> following
>>> /// values can be specified.
>>> /// </summary>
>>> [Flags]
>>> private enum LimitFlags
>>> {
>>> /// <summary>
>>> /// Causes all processes associated with the job to use the same
>>> minimum and maximum working set sizes.
>>> /// </summary>
>>> LimitWorkingSet = 0x00000001,
>>>
>>> /// <summary>
>>> /// Establishes a user-mode execution time limit for each
>>> currently active process
>>> /// and for all future processes associated with the job.
>>> /// </summary>
>>> LimitProcessTime = 0x00000002,
>>>
>>> /// <summary>
>>> /// Establishes a user-mode execution time limit for the job. This
>>> flag cannot
>>> /// be used with JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME.
>>> /// </summary>
>>> LimitJobTime = 0x00000004,
>>>
>>> /// <summary>
>>> /// Establishes a maximum number of simultaneously active
>>> processes associated
>>> /// with the job.
>>> /// </summary>
>>> LimitActiveProcesses = 0x00000008,
>>>
>>> /// <summary>
>>> /// Causes all processes associated with the job to use the same
>>> processor
>>> /// affinity.
>>> /// </summary>
>>> LimitAffinity = 0x00000010,
>>>
>>> /// <summary>
>>> /// Causes all processes associated with the job to use the same
>>> priority class.
>>> /// For more information, see Scheduling Priorities.
>>> /// </summary>
>>> LimitPriorityClass = 0x00000020,
>>>
>>> /// <summary>
>>> /// Preserves any job time limits you previously set. As long as
>>> this flag is
>>> /// set, you can establish a per-job time limit once, then alter
>>> other limits
>>> /// in subsequent calls. This flag cannot be used with
>>> JOB_OBJECT_LIMIT_JOB_TIME.
>>> /// </summary>
>>> PreserveJobTime = 0x00000040,
>>>
>>> /// <summary>
>>> /// Causes all processes in the job to use the same scheduling
>>> class.
>>> /// </summary>
>>> LimitSchedulingClass = 0x00000080,
>>>
>>> /// <summary>
>>> /// Causes all processes associated with the job to limit their
>>> committed memory.
>>> /// When a process attempts to commit memory that would exceed the
>>> per-process
>>> /// limit, it fails. If the job object is associated with a
>>> completion port, a
>>> /// JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT message is sent to the
>>> completion port.
>>> /// This limit requires use of a
>>> JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure.
>>> /// Its BasicLimitInformation member is a
>>> JOBOBJECT_BASIC_LIMIT_INFORMATION
>>> /// structure.
>>> /// </summary>
>>> LimitProcessMemory = 0x00000100,
>>>
>>> /// <summary>
>>> /// Causes all processes associated with the job to limit the
>>> job-wide sum of
>>> /// their committed memory. When a process attempts to commit
>>> memory that would
>>> /// exceed the job-wide limit, it fails. If the job object is
>>> associated with a
>>> /// completion port, a JOB_OBJECT_MSG_JOB_MEMORY_LIMIT message is
>>> sent to the
>>> /// completion port. This limit requires use of a
>>> /// JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure. Its
>>> BasicLimitInformation
>>> /// member is a JOBOBJECT_BASIC_LIMIT_INFORMATION structure.
>>> /// </summary>
>>> LimitJobMemory = 0x00000200,
>>>
>>> /// <summary>
>>> /// Forces a call to the SetErrorMode function with the
>>> SEM_NOGPFAULTERRORBOX
>>> /// flag for each process associated with the job. If an
>>> exception occurs and
>>> /// the system calls the UnhandledExceptionFilter function, the
>>> debugger will
>>> /// be given a chance to act. If there is no debugger, the
>>> functions returns
>>> /// EXCEPTION_EXECUTE_HANDLER. Normally, this will cause
>>> termination of the
>>> /// process with the exception code as the exit status. This
>>> limit requires
>>> /// use of a JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure. Its
>>> /// BasicLimitInformation member is a
>>> JOBOBJECT_BASIC_LIMIT_INFORMATION structure.
>>> /// </summary>
>>> DieOnUnhandledException = 0x00000400,
>>>
>>> /// <summary>
>>> /// If any process associated with the job creates a child process
>>> using the
>>> /// CREATE_BREAKAWAY_FROM_JOB flag while this limit is in effect,
>>> the child
>>> /// process is not associated with the job. This limit requires
>>> use of a
>>> /// JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure. Its
>>> BasicLimitInformation
>>> /// member is a JOBOBJECT_BASIC_LIMIT_INFORMATION structure.
>>> /// </summary>
>>> LimitBreakawayOk = 0x00000800,
>>>
>>> /// <summary>
>>> /// Allows any process associated with the job to create child
>>> processes
>>> /// that are not associated with the job. This limit requires use
>>> of a
>>> /// JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure. Its
>>> BasicLimitInformation
>>> /// member is a JOBOBJECT_BASIC_LIMIT_INFORMATION structure.
>>> /// </summary>
>>> LimitSilentBreakawayOk = 0x00001000,
>>>
>>> /// <summary>
>>> /// Causes all processes associated with the job to terminate when
>>> the last
>>> /// handle to the job is closed. This limit requires use of a
>>> /// JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure. Its
>>> BasicLimitInformation
>>> /// member is a JOBOBJECT_BASIC_LIMIT_INFORMATION structure.
>>> /// Windows 2000: This flag is not supported.
>>> /// </summary>
>>> LimitKillOnJobClose = 0x00002000
>>> }
>>> #endregion
>>>
>>> #region IoCounters Structures
>>> /// <summary>
>>> /// Various counters for different types of IO operations. Don't
>>> believe
>>> /// this is currently implemented by Windows.
>>> /// </summary>
>>> [StructLayout(LayoutKind.Explicit)]
>>> private struct IoCounters32
>>> {
>>> /// <summary>
>>> /// The number of read operations.
>>> /// </summary>
>>> [FieldOffset(0)]
>>> public ulong ReadOperationCount;
>>>
>>> /// <summary>
>>> /// The number of write operations.
>>> /// </summary>
>>> [FieldOffset(8)]
>>> public ulong WriteOperationCount;
>>>
>>> /// <summary>
>>> /// The number of other operations.
>>> /// </summary>
>>> [FieldOffset(16)]
>>> public ulong OtherOperationCount;
>>>
>>> /// <summary>
>>> /// The number of read transfers.
>>> /// </summary>
>>> [FieldOffset(24)]
>>> public ulong ReadTransferCount;
>>>
>>> /// <summary>
>>> /// The number of write transfers.
>>> /// </summary>
>>> [FieldOffset(32)]
>>> public ulong WriteTransferCount;
>>>
>>> /// <summary>
>>> /// The number of other transfers.
>>> /// </summary>
>>> [FieldOffset(40)]
>>> public ulong OtherTransferCount;
>>> }
>>>
>>> /// <summary>
>>> /// Various counters for different types of IO operations. Don't
>>> believe
>>> /// this is currently implemented by Windows.
>>> /// </summary>
>>> [StructLayout(LayoutKind.Explicit)]
>>> private struct IoCounters64
>>> {
>>> /// <summary>
>>> /// The number of read operations.
>>> /// </summary>
>>> [FieldOffset(0)]
>>> public ulong ReadOperationCount;
>>>
>>> /// <summary>
>>> /// The number of write operations.
>>> /// </summary>
>>> [FieldOffset(8)]
>>> public ulong WriteOperationCount;
>>>
>>> /// <summary>
>>> /// The number of other operations.
>>> /// </summary>
>>> [FieldOffset(16)]
>>> public ulong OtherOperationCount;
>>>
>>> /// <summary>
>>> /// The number of read transfers.
>>> /// </summary>
>>> [FieldOffset(24)]
>>> public ulong ReadTransferCount;
>>>
>>> /// <summary>
>>> /// The number of write transfers.
>>> /// </summary>
>>> [FieldOffset(32)]
>>> public ulong WriteTransferCount;
>>>
>>> /// <summary>
>>> /// The number of other transfers.
>>> /// </summary>
>>> [FieldOffset(40)]
>>> public ulong OtherTransferCount;
>>> }
>>> #endregion
>>>
>>> #region BasicLimits Structures
>>> /// <summary>
>>> /// The JOBOBJECT_BASIC_LIMIT_INFORMATION structure contains basic
>>> limit
>>> /// information for a job object.
>>> /// </summary>
>>> [StructLayout(LayoutKind.Explicit)]
>>> private struct BasicLimits32
>>> {
>>> /// <summary>
>>> /// If LimitFlags specifies JOB_OBJECT_LIMIT_PROCESS_TIME, this
>>> member is
>>> /// the per-process user-mode execution time limit, in
>>> 100-nanosecond ticks.
>>> /// Otherwise, this member is ignored. The system periodically
>>> checks to
>>> /// determine whether each process associated with the job has
>>> accumulated
>>> /// more user-mode time than the set limit. If it has, the process
>>> is terminated.
>>> /// </summary>
>>> [FieldOffset(0)]
>>> public long PerProcessUserTimeLimit;
>>>
>>> /// <summary>
>>> /// If LimitFlags specifies JOB_OBJECT_LIMIT_JOB_TIME, this member
>>> is the
>>> /// per-job user-mode execution time limit, in 100-nanosecond
>>> ticks. Otherwise,
>>> /// this member is ignored. The system adds the current time of
>>> the processes
>>> /// associated with the job to this limit. For example, if you set
>>> this limit
>>> /// to 1 minute, and the job has a process that has accumulated 5
>>> minutes of
>>> /// user-mode time, the limit actually enforced is 6 minutes. The
>>> system
>>> /// periodically checks to determine whether the sum of the
>>> user-mode execution
>>> /// time for all processes is greater than this end-of-job limit.
>>> If it is, the
>>> /// action specified in the EndOfJobTimeAction member of the
>>> /// JOBOBJECT_END_OF_JOB_TIME_INFORMATION structure is carried
>>> out. By default,
>>> /// all processes are terminated and the status code is set to
>>> /// ERROR_NOT_ENOUGH_QUOTA.
>>> /// </summary>
>>> [FieldOffset(8)]
>>> public long PerJobUserTimeLimit;
>>>
>>> /// <summary>
>>> /// Limit flags that are in effect. This member is a bit field
>>> that determines
>>> /// whether other structure members are used. Any combination
>>> LimitFlag values
>>> /// can be specified.
>>> /// </summary>
>>> [FieldOffset(16)]
>>> public LimitFlags LimitFlags;
>>>
>>> /// <summary>
>>> /// If LimitFlags specifies JOB_OBJECT_LIMIT_WORKINGSET, this
>>> member is the
>>> /// minimum working set size for each process associated with the
>>> job. Otherwise,
>>> /// this member is ignored. If MaximumWorkingSetSize is nonzero,
>>> /// MinimumWorkingSetSize cannot be zero.
>>> /// </summary>
>>> [FieldOffset(20)]
>>> public uint MinimumWorkingSetSize;
>>>
>>> /// <summary>
>>> /// If LimitFlags specifies JOB_OBJECT_LIMIT_WORKINGSET, this
>>> member is the
>>> /// maximum working set size for each process associated with the
>>> job. Otherwise,
>>> /// this member is ignored. If MinimumWorkingSetSize is nonzero,
>>> /// MaximumWorkingSetSize cannot be zero.
>>> /// </summary>
>>> [FieldOffset(24)]
>>> public uint MaximumWorkingSetSize;
>>>
>>> /// <summary>
>>> /// If LimitFlags specifies JOB_OBJECT_LIMIT_ACTIVE_PROCESS, this
>>> member is the
>>> /// active process limit for the job. Otherwise, this member is
>>> ignored. If you
>>> /// try to associate a process with a job, and this causes the
>>> active process
>>> /// count to exceed this limit, the process is terminated and the
>>> association
>>> /// fails.
>>> /// </summary>
>>> [FieldOffset(28)]
>>> public int ActiveProcessLimit;
>>>
>>> /// <summary>
>>> /// If LimitFlags specifies JOB_OBJECT_LIMIT_AFFINITY, this member
>>> is the
>>> /// processor affinity for all processes associated with the job.
>>> Otherwise,
>>> /// this member is ignored. The affinity must be a proper subset
>>> of the system
>>> /// affinity mask obtained by calling the GetProcessAffinityMask
>>> function. The
>>> /// affinity of each thread is set to this value, but threads are
>>> free to
>>> /// subsequently set their affinity, as long as it is a subset of
>>> the specified
>>> /// affinity mask. Processes cannot set their own affinity mask.
>>> /// </summary>
>>> [FieldOffset(32)]
>>> public IntPtr Affinity;
>>>
>>> /// <summary>
>>> /// If LimitFlags specifies JOB_OBJECT_LIMIT_PRIORITY_CLASS, this
>>> member is the
>>> /// priority class for all processes associated with the job.
>>> Otherwise, this
>>> /// member is ignored. Processes and threads cannot modify their
>>> priority class.
>>> /// The calling process must enable the SE_INC_BASE_PRIORITY_NAME
>>> privilege.
>>> /// </summary>
>>> [FieldOffset(36)]
>>> public int PriorityClass;
>>>
>>> /// <summary>
>>> /// If LimitFlags specifies JOB_OBJECT_LIMIT_SCHEDULING_CLASS,
>>> this member is
>>> /// the scheduling class for all processes associated with the
>>> job. Otherwise,
>>> /// this member is ignored. The valid values are 0 to 9. Use 0
>>> for the least
>>> /// favorable scheduling class relative to other threads, and 9
>>> for the most
>>> /// favorable scheduling class relative to other threads. By
>>> default, this
>>> /// value is 5. To use a scheduling class greater than 5, the
>>> calling process
>>> /// must enable the SE_INC_BASE_PRIORITY_NAME privilege.
>>> /// </summary>
>>> [FieldOffset(40)]
>>> public int SchedulingClass;
>>> }
>>>
>>> /// <summary>
>>> /// The JOBOBJECT_BASIC_LIMIT_INFORMATION structure contains basic
>>> limit
>>> /// information for a job object.
>>> /// </summary>
>>> [StructLayout(LayoutKind.Explicit)]
>>> private struct BasicLimits64
>>> {
>>> /// <summary>
>>> /// If LimitFlags specifies JOB_OBJECT_LIMIT_PROCESS_TIME, this
>>> member is
>>> /// the per-process user-mode execution time limit, in
>>> 100-nanosecond ticks.
>>> /// Otherwise, this member is ignored. The system periodically
>>> checks to
>>> /// determine whether each process associated with the job has
>>> accumulated
>>> /// more user-mode time than the set limit. If it has, the process
>>> is terminated.
>>> /// </summary>
>>> [FieldOffset(0)]
>>> public long PerProcessUserTimeLimit;
>>>
>>> /// <summary>
>>> /// If LimitFlags specifies JOB_OBJECT_LIMIT_JOB_TIME, this member
>>> is the
>>> /// per-job user-mode execution time limit, in 100-nanosecond
>>> ticks. Otherwise,
>>> /// this member is ignored. The system adds the current time of
>>> the processes
>>> /// associated with the job to this limit. For example, if you set
>>> this limit
>>> /// to 1 minute, and the job has a process that has accumulated 5
>>> minutes of
>>> /// user-mode time, the limit actually enforced is 6 minutes. The
>>> system
>>> /// periodically checks to determine whether the sum of the
>>> user-mode execution
>>> /// time for all processes is greater than this end-of-job limit.
>>> If it is, the
>>> /// action specified in the EndOfJobTimeAction member of the
>>> /// JOBOBJECT_END_OF_JOB_TIME_INFORMATION structure is carried
>>> out. By default,
>>> /// all processes are terminated and the status code is set to
>>> /// ERROR_NOT_ENOUGH_QUOTA.
>>> /// </summary>
>>> [FieldOffset(8)]
>>> public long PerJobUserTimeLimit;
>>>
>>> /// <summary>
>>> /// Limit flags that are in effect. This member is a bit field
>>> that determines
>>> /// whether other structure members are used. Any combination
>>> LimitFlag values
>>> /// can be specified.
>>> /// </summary>
>>> [FieldOffset(16)]
>>> public LimitFlags LimitFlags;
>>>
>>> /// <summary>
>>> /// If LimitFlags specifies JOB_OBJECT_LIMIT_WORKINGSET, this
>>> member is the
>>> /// minimum working set size for each process associated with the
>>> job. Otherwise,
>>> /// this member is ignored. If MaximumWorkingSetSize is nonzero,
>>> /// MinimumWorkingSetSize cannot be zero.
>>> /// </summary>
>>> [FieldOffset(24)]
>>> public ulong MinimumWorkingSetSize;
>>>
>>> /// <summary>
>>> /// If LimitFlags specifies JOB_OBJECT_LIMIT_WORKINGSET, this
>>> member is the
>>> /// maximum working set size for each process associated with the
>>> job. Otherwise,
>>> /// this member is ignored. If MinimumWorkingSetSize is nonzero,
>>> /// MaximumWorkingSetSize cannot be zero.
>>> /// </summary>
>>> [FieldOffset(32)]
>>> public ulong MaximumWorkingSetSize;
>>>
>>> /// <summary>
>>> /// If LimitFlags specifies JOB_OBJECT_LIMIT_ACTIVE_PROCESS, this
>>> member is the
>>> /// active process limit for the job. Otherwise, this member is
>>> ignored. If you
>>> /// try to associate a process with a job, and this causes the
>>> active process
>>> /// count to exceed this limit, the process is terminated and the
>>> association
>>> /// fails.
>>> /// </summary>
>>> [FieldOffset(40)]
>>> public int ActiveProcessLimit;
>>>
>>> /// <summary>
>>> /// If LimitFlags specifies JOB_OBJECT_LIMIT_AFFINITY, this member
>>> is the
>>> /// processor affinity for all processes associated with the job.
>>> Otherwise,
>>> /// this member is ignored. The affinity must be a proper subset
>>> of the system
>>> /// affinity mask obtained by calling the GetProcessAffinityMask
>>> function. The
>>> /// affinity of each thread is set to this value, but threads are
>>> free to
>>> /// subsequently set their affinity, as long as it is a subset of
>>> the specified
>>> /// affinity mask. Processes cannot set their own affinity mask.
>>> /// </summary>
>>> [FieldOffset(48)]
>>> public IntPtr Affinity;
>>>
>>> /// <summary>
>>> /// If LimitFlags specifies JOB_OBJECT_LIMIT_PRIORITY_CLASS, this
>>> member is the
>>> /// priority class for all processes associated with the job.
>>> Otherwise, this
>>> /// member is ignored. Processes and threads cannot modify their
>>> priority class.
>>> /// The calling process must enable the SE_INC_BASE_PRIORITY_NAME
>>> privilege.
>>> /// </summary>
>>> [FieldOffset(56)]
>>> public int PriorityClass;
>>>
>>> /// <summary>
>>> /// If LimitFlags specifies JOB_OBJECT_LIMIT_SCHEDULING_CLASS,
>>> this member is
>>> /// the scheduling class for all processes associated with the
>>> job. Otherwise,
>>> /// this member is ignored. The valid values are 0 to 9. Use 0
>>> for the least
>>> /// favorable scheduling class relative to other threads, and 9
>>> for the most
>>> /// favorable scheduling class relative to other threads. By
>>> default, this
>>> /// value is 5. To use a scheduling class greater than 5, the
>>> calling process
>>> /// must enable the SE_INC_BASE_PRIORITY_NAME privilege.
>>> /// </summary>
>>> [FieldOffset(60)]
>>> public int SchedulingClass;
>>> }
>>> #endregion
>>>
>>> #region ExtendedLimits Structures
>>> /// <summary>
>>> /// The JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure contains
>>> basic and extended limit
>>> /// information for a job object.
>>> /// </summary>
>>> [StructLayout(LayoutKind.Explicit)]
>>> private struct ExtendedLimits32
>>> {
>>> /// <summary>
>>> /// A JOBOBJECT_BASIC_LIMIT_INFORMATION structure that contains
>>> /// basic limit information.
>>> /// </summary>
>>> [FieldOffset(0)]
>>> public BasicLimits32 BasicLimits;
>>>
>>> /// <summary>
>>> /// Resereved.
>>> /// </summary>
>>> [FieldOffset(48)]
>>> public IoCounters32 IoInfo;
>>>
>>> /// <summary>
>>> /// If the LimitFlags member of the
>>> JOBOBJECT_BASIC_LIMIT_INFORMATION structure
>>> /// specifies the JOB_OBJECT_LIMIT_PROCESS_MEMORY value, this
>>> member specifies
>>> /// the limit for the virtual memory that can be committed by a
>>> process.
>>> /// Otherwise, this member is ignored.
>>> /// </summary>
>>> [FieldOffset(96)]
>>> public uint ProcessMemoryLimit;
>>>
>>> /// <summary>
>>> /// If the LimitFlags member of the
>>> JOBOBJECT_BASIC_LIMIT_INFORMATION structure
>>> /// specifies the JOB_OBJECT_LIMIT_JOB_MEMORY value, this member
>>> specifies the
>>> /// limit for the virtual memory that can be committed for the
>>> job. Otherwise,
>>> /// this member is ignored.
>>> /// </summary>
>>> [FieldOffset(100)]
>>> public uint JobMemoryLimit;
>>>
>>> /// <summary>
>>> /// Peak memory used by any process ever associated with the job.
>>> /// </summary>
>>> [FieldOffset(104)]
>>> public uint PeakProcessMemoryUsed;
>>>
>>> /// <summary>
>>> /// Peak memory usage of all processes currently associated with
>>> the job.
>>> /// </summary>
>>> [FieldOffset(108)]
>>> public uint PeakJobMemoryUsed;
>>> }
>>>
>>> /// <summary>
>>> /// The JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure contains
>>> basic and extended limit
>>> /// information for a job object.
>>> /// </summary>
>>> [StructLayout(LayoutKind.Explicit)]
>>> private struct ExtendedLimits64
>>> {
>>> /// <summary>
>>> /// A JOBOBJECT_BASIC_LIMIT_INFORMATION structure that contains
>>> /// basic limit information.
>>> /// </summary>
>>> [FieldOffset(0)]
>>> public BasicLimits64 BasicLimits;
>>>
>>> /// <summary>
>>> /// Resereved.
>>> /// </summary>
>>> [FieldOffset(64)]
>>> public IoCounters64 IoInfo;
>>>
>>> /// <summary>
>>> /// If the LimitFlags member of the
>>> JOBOBJECT_BASIC_LIMIT_INFORMATION structure
>>> /// specifies the JOB_OBJECT_LIMIT_PROCESS_MEMORY value, this
>>> member specifies
>>> /// the limit for the virtual memory that can be committed by a
>>> process.
>>> /// Otherwise, this member is ignored.
>>> /// </summary>
>>> [FieldOffset(112)]
>>> public ulong ProcessMemoryLimit;
>>>
>>> /// <summary>
>>> /// If the LimitFlags member of the
>>> JOBOBJECT_BASIC_LIMIT_INFORMATION structure
>>> /// specifies the JOB_OBJECT_LIMIT_JOB_MEMORY value, this member
>>> specifies the
>>> /// limit for the virtual memory that can be committed for the
>>> job. Otherwise,
>>> /// this member is ignored.
>>> /// </summary>
>>> [FieldOffset(120)]
>>> public ulong JobMemoryLimit;
>>>
>>> /// <summary>
>>> /// Peak memory used by any process ever associated with the job.
>>> /// </summary>
>>> [FieldOffset(128)]
>>> public ulong PeakProcessMemoryUsed;
>>>
>>> /// <summary>
>>> /// Peak memory usage of all processes currently associated with
>>> the job.
>>> /// </summary>
>>> [FieldOffset(136)]
>>> public ulong PeakJobMemoryUsed;
>>> }
>>> #endregion
>>>
>>> #region JobObjectInfo Union
>>> /// <summary>
>>> /// Union of different limit data structures that may be passed
>>> /// to SetInformationJobObject / from QueryInformationJobObject.
>>> /// This union also contains separate 32 and 64 bit versions of
>>> /// each structure.
>>> /// </summary>
>>> [StructLayout(LayoutKind.Explicit)]
>>> private struct JobObjectInfo
>>> {
>>> #region 32 bit structures
>>> /// <summary>
>>> /// The BasicLimits32 structure contains basic limit information
>>> /// for a job object on a 32bit platform.
>>> /// </summary>
>>> [FieldOffset(0)]
>>> public BasicLimits32 basicLimits32;
>>>
>>> /// <summary>
>>> /// The ExtendedLimits32 structure contains extended limit
>>> information
>>> /// for a job object on a 32bit platform.
>>> /// </summary>
>>> [FieldOffset(0)]
>>> public ExtendedLimits32 extendedLimits32;
>>> #endregion
>>>
>>> #region 64 bit structures
>>> /// <summary>
>>> /// The BasicLimits64 structure contains basic limit information
>>> /// for a job object on a 64bit platform.
>>> /// </summary>
>>> [FieldOffset(0)]
>>> public BasicLimits64 basicLimits64;
>>>
>>> /// <summary>
>>> /// The ExtendedLimits64 structure contains extended limit
>>> information
>>> /// for a job object on a 64bit platform.
>>> /// </summary>
>>> [FieldOffset(0)]
>>> public ExtendedLimits64 extendedLimits64;
>>> #endregion
>>> }
>>> #endregion
>>>
>>> #region WinAPI Class
>>> /// <summary>
>>> /// Private class that holds all the Windows API calls made by this
>>> /// </summary>
>>> private class WinAPI
>>> {
>>> /// <summary>
>>> /// This function returns a pseudohandle for the current process.
>>> /// </summary>
>>> /// <returns>The return value is a pseudohandle to the current
>>> process.</returns>
>>> [DllImport("kernel32.dll", SetLastError = true)]
>>> public static extern IntPtr GetCurrentProcess();
>>>
>>> /// <summary>
>>> /// The IsProcessInJob function determines if the process is
>>> running in the specified job.
>>> /// </summary>
>>> /// <param name="processHandle">Handle to the process to be
>>> tested.
>>> /// The handle must have the PROCESS_QUERY_INFORMATION access
>>> right.
>>> /// For more information, see Process Security and Access
>>> Rights.</param>
>>> /// <param name="jobHandle">Handle to the job. If this parameter
>>> is NULL,
>>> /// the function tests if the process is running under any job.
>>> If this
>>> /// parameter is not NULL, the handle must have the
>>> JOB_OBJECT_QUERY access
>>> /// right. For more information, see Job Object Security and
>>> Access Rights.</param>
>>> /// <param name="result">Pointer to a value that receives TRUE if
>>> the process
>>> /// is running in the job, and FALSE otherwise.</param>
>>> /// <returns>If the function succeeds, the return value is
>>> nonzero.
>>> /// If the function fails, the return value is zero. To get
>>> extended error information,
>>> /// call GetLastError.</returns>
>>> [DllImport("kernel32.dll", SetLastError = true)]
>>> public static extern bool IsProcessInJob(
>>> IntPtr processHandle,
>>> IntPtr jobHandle,
>>> [Out] out bool result);
>>>
>>> /// <summary>
>>> /// The CreateJobObject function creates or opens a job object.
>>> /// </summary>
>>> /// <param name="jobAttributes">Pointer to a SECURITY_ATTRIBUTES
>>> structure that
>>> /// specifies the security descriptor for the job object and
>>> determines whether
>>> /// child processes can inherit the returned handle. If
>>> lpJobAttributes is NULL,
>>> /// the job object gets a default security descriptor and the
>>> handle cannot be inherited.
>>> /// The ACLs in the default security descriptor for a job object
>>> come from the primary
>>> /// or impersonation token of the creator.</param>
>>> /// <param name="name"> Pointer to a null-terminated string
>>> specifying the name of the
>>> /// job. The name is limited to MAX_PATH characters. Name
>>> comparison is case-sensitive.
>>> /// If lpName is NULL, the job is created without a name. If
>>> lpName matches the name
>>> /// of an existing event, semaphore, mutex, waitable timer, or
>>> file-mapping object, the
>>> /// function fails and the GetLastError function returns
>>> ERROR_INVALID_HANDLE. This
>>> /// occurs because these objects share the same name
>>> space.</param>
>>> /// <returns>If the function succeeds, the return value is a
>>> handle to the job object.
>>> /// The handle has the JOB_OBJECT_ALL_ACCESS access right. If the
>>> object existed before
>>> /// the function call, the function returns a handle to the
>>> existing job object and
>>> /// GetLastError returns ERROR_ALREADY_EXISTS. If the function
>>> fails, the return value
>>> /// is NULL. To get extended error information, call
>>> GetLastError.</returns>
>>> [DllImport("kernel32.dll", SetLastError = true)]
>>> public static extern IntPtr CreateJobObject(
>>> IntPtr jobAttributes,
>>> string name);
>>>
>>> /// <summary>
>>> /// The AssignProcessToJobObject function assigns a process to an
>>> existing job object.
>>> /// </summary>
>>> /// <param name="jobHandle">Handle to the job object to which the
>>> process will be
>>> /// associated. The CreateJobObject or OpenJobObject function
>>> returns this handle.
>>> /// The handle must have the JOB_OBJECT_ASSIGN_PROCESS access
>>> right. For more
>>> /// information, see Job Object Security and Access
>>> Rights.</param>
>>> /// <param name="processHandle">Handle to the process to associate
>>> with the job object.
>>> /// The process must not already be assigned to a job. The handle
>>> must have the
>>> /// PROCESS_SET_QUOTA and PROCESS_TERMINATE access rights. For
>>> more information,
>>> /// see Process Security and Access Rights.</param>
>>> /// <returns>If the function succeeds, the return value is
>>> nonzero. If the function
>>> /// fails, the return value is zero. To get extended error
>>> information, call
>>> /// GetLastError.</returns>
>>> [DllImport("kernel32.dll", SetLastError = true)]
>>> public static extern bool AssignProcessToJobObject(
>>> IntPtr jobHandle,
>>> IntPtr processHandle);
>>>
>>> /// <summary>
>>> /// The QueryInformationJobObject function retrieves limit and job
>>> state information
>>> /// from the job object.
>>> /// </summary>
>>> /// <param name="jobHandle">Handle to the job whose information is
>>> being queried.
>>> /// The CreateJobObject or OpenJobObject function returns this
>>> handle. The handle
>>> /// must have the JOB_OBJECT_QUERY access right. For more
>>> information, see Job
>>> /// Object Security and Access Rights. If this value is NULL and
>>> the calling
>>> /// process is associated with a job, the job associated with the
>>> calling process
>>> /// is used.</param>
>>> /// <param name="jobObjectInfoClass">Information class for the
>>> limits to be set. This
>>> /// parameter can be one of the following values.</param>
>>> /// <param name="jobObjectInfo">Limit information. The format of
>>> this data
>>> /// depends on the value of the JobObjectInfoClass
>>> parameter.</param>
>>> /// <param name="jobObjectInfoLength">Count of the job information
>>> being queried, in
>>> /// bytes.</param>
>>> /// <param name="returnLength">Pointer to a variable that receives
>>> the length of data
>>> /// written to the structure pointed to by the lpJobObjectInfo
>>> parameter. If you
>>> /// do not want to receive this information, specify NULL.</param>
>>> /// <returns>If the function succeeds, the return value is
>>> nonzero. If the
>>> /// function fails, the return value is zero. To get extended
>>> error information,
>>> /// call GetLastError.</returns>
>>> [DllImport("kernel32.dll", SetLastError = true)]
>>> public static extern bool QueryInformationJobObject(
>>> [In] IntPtr jobHandle,
>>> [In] JobObjectInfoClass jobObjectInfoClass,
>>> [Out] out JobObjectInfo jobObjectInfo,
>>> [In] int jobObjectInfoLength,
>>> [Out] out int returnLength);
>>>
>>> /// <summary>
>>> /// The SetInformationJobObject function sets limits for a job
>>> object.
>>> /// </summary>
>>> /// <param name="jobHandle">Handle to the job whose limits are
>>> being set.
>>> /// The CreateJobObject or OpenJobObject function returns this
>>> handle. The handle must
>>> /// have the JOB_OBJECT_SET_ATTRIBUTES access right. For more
>>> information, see Job
>>> /// Object Security and Access Rights.</param>
>>> /// <param name="jobObjectInfoClass">Information class for the
>>> limits to be set. This
>>> /// parameter can be one of the following values.</param>
>>> /// <param name="jobObjectInfo">Limits to be set for the job. The
>>> format of this data
>>> /// depends on the value of JobObjectInfoClass.</param>
>>> /// <param name="jobObjectInfoLength">Size of the job information
>>> being set, in
>>> /// bytes.</param>
>>> /// <returns>If the function succeeds, the return value is
>>> nonzero. If the function
>>> /// fails, the return value is zero. To get extended error
>>> information,
>>> /// call GetLastError.</returns>
>>> [DllImport("kernel32.dll", SetLastError = true)]
>>> public static extern bool SetInformationJobObject(
>>> [In] IntPtr jobHandle,
>>> [In] JobObjectInfoClass jobObjectInfoClass,
>>> [In] ref JobObjectInfo jobObjectInfo,
>>> [In] int jobObjectInfoLength);
>>>
>>> /// <summary>
>>> /// The CloseHandle function lets us destroy a JobObject handle.
>>> /// </summary>
>>> /// <param name="jobHandle">Handle to the job</param>
>>> /// <returns>If the function succeeds, the return value true. If
>>> the function
>>> /// fails, the return value is false. To get extended error
>>> information,
>>> /// call GetLastError.</returns>
>>> [DllImport("kernel32.dll", SetLastError=true)]
>>> public static extern bool CloseHandle(
>>> [In] IntPtr jobHandle);
>>> }
>>> #endregion
>>>
>>> #region State
>>> /// <summary>
>>> /// This is a pseudo handle to the currently running process.
>>> /// </summary>
>>> static private readonly IntPtr currentProcessHandle =
>>> WinAPI.GetCurrentProcess();
>>>
>>> /// <summary>
>>> /// This is a pseudo handle to the "any" job object handle.
>>> /// </summary>
>>> static private readonly IntPtr anyJobHandle = IntPtr.Zero;
>>>
>>> /// <summary>
>>> /// The job created for this process.
>>> /// </summary>
>>> static private IntPtr currentJobHandle = IntPtr.Zero;
>>> #endregion
>>>
>>> #region Controlling Methods
>>> /// <summary>
>>> /// Checks to see if the current process is a member of any Windows
>>> job.
>>> /// </summary>
>>> /// <returns>True if the current process is a member of a job, false
>>> otherwise</returns>
>>> static public bool IsCurrentProcessMemberOfAnyJob()
>>> {
>>> bool isInJob;
>>> bool result;
>>>
>>> result = WinAPI.IsProcessInJob(
>>> currentProcessHandle,
>>> anyJobHandle,
>>> out isInJob);
>>>
>>> if (!result)
>>> {
>>> int error = Marshal.GetLastWin32Error();
>>> throw new ApplicationException("Failed calling IsProcessInJob,
>>> error = " + error);
>>> }
>>>
>>> return isInJob;
>>> }
>>>
>>> /// <summary>
>>> /// Creates a new job object and assigns the current process to that
>>> job.
>>> /// </summary>
>>> static public void CreateNewJobForCurrentProcess()
>>> {
>>> IntPtr currentProcessHandle = WinAPI.GetCurrentProcess();
>>> IntPtr newJobHandle = WinAPI.CreateJobObject(
>>> IntPtr.Zero,
>>> null);
>>>
>>> if (newJobHandle == IntPtr.Zero)
>>> {
>>> int error = Marshal.GetLastWin32Error();
>>> throw new ApplicationException("Failed calling CreateJobObject,
>>> error = " + error);
>>> }
>>>
>>> bool result = WinAPI.AssignProcessToJobObject(
>>> newJobHandle,
>>> currentProcessHandle);
>>>
>>> if (!result)
>>> {
>>> int error = Marshal.GetLastWin32Error();
>>> throw new ApplicationException("Failed calling
>>> AssignProcessToJobObject, error = " + error);
>>> }
>>>
>>> currentJobHandle = newJobHandle;
>>> }
>>>
>>> /// <summary>
>>> /// Gets the current process memory limit settings for the job
>>> object the
>>> /// current process belongs to.
>>> /// </summary>
>>> /// <param name="processMemoryLimit">Out parameter set to the
>>> maximum amount of
>>> /// commit memory a single individual process in the job may consume
>>> in bytes.</param>
>>> /// <returns>True if the limit is enforced, false
>>> otherwise.</returns>
>>> static public bool GetProcessMemoryLimit(out ulong
>>> processMemoryLimit)
>>> {
>>> JobObjectInfo jobObjectInfo;
>>> IntPtr currentJob = IntPtr.Zero;
>>> bool result;
>>> int returnLength;
>>>
>>> if (Is32Bit)
>>> {
>>> result = WinAPI.QueryInformationJobObject(
>>> currentJobHandle,
>>> JobObjectInfoClass.ExtendedLimitInformation,
>>> out jobObjectInfo,
>>> Marshal.SizeOf(typeof(ExtendedLimits32)),
>>> out returnLength
>>> );
>>>
>>> if (!result)
>>> {
>>> int error = Marshal.GetLastWin32Error();
>>> throw new ApplicationException("Failed calling
>>> QueryInformationJobObject, error = " + error);
>>> }
>>>
>>> Trace.Assert(
>>> returnLength == Marshal.SizeOf(typeof(ExtendedLimits32)),
>>> "QueryInformationJobObject returned " + returnLength + " bytes
>>> instead of expected " +
>>> Marshal.SizeOf(typeof(ExtendedLimits32))
>>> );
>>>
>>> processMemoryLimit =
>>> jobObjectInfo.extendedLimits32.ProcessMemoryLimit;
>>> return (jobObjectInfo.basicLimits32.LimitFlags &
>>> LimitFlags.LimitProcessMemory) != 0;
>>> }
>>> else
>>> {
>>> result = WinAPI.QueryInformationJobObject(
>>> currentJobHandle,
>>> JobObjectInfoClass.BasicLimitInformation,
>>> out jobObjectInfo,
>>> Marshal.SizeOf(typeof(BasicLimits64)),
>>> out returnLength
>>> );
>>>
>>> if (!result)
>>> {
>>> int error = Marshal.GetLastWin32Error();
>>> throw new ApplicationException("Failed calling
>>> QueryInformationJobObject, error = " + error);
>>> }
>>>
>>> result = WinAPI.QueryInformationJobObject(
>>> currentJobHandle,
>>> JobObjectInfoClass.ExtendedLimitInformation,
>>> out jobObjectInfo,
>>> Marshal.SizeOf(typeof(ExtendedLimits64)),
>>> out returnLength
>>> );
>>>
>>> if (!result)
>>> {
>>> int error = Marshal.GetLastWin32Error();
>>> throw new ApplicationException("Failed calling
>>> QueryInformationJobObject, error = " + error);
>>> }
>>>
>>> Trace.Assert(
>>> returnLength == Marshal.SizeOf(typeof(ExtendedLimits64)),
>>> "QueryInformationJobObject returned " + returnLength + " bytes
>>> instead of expected " +
>>> Marshal.SizeOf(typeof(ExtendedLimits64))
>>> );
>>>
>>> processMemoryLimit =
>>> jobObjectInfo.extendedLimits64.ProcessMemoryLimit;
>>> return (jobObjectInfo.basicLimits64.LimitFlags &
>>> LimitFlags.LimitProcessMemory) != 0;
>>> }
>>> }
>>>
>>> /// <summary>
>>> /// Set the process memory limit in the current job to the given
>>> value.
>>> /// </summary>
>>> /// <param name="processMemoryLimit">The maximum amount of commit
>>> memory a
>>> /// single individual process in the job may consume in
>>> bytes.</param>
>>> static public void SetProcessMemoryLimit(ulong processMemoryLimit)
>>> {
>>> ChangeJob(ji =>
>>> {
>>> Trace.Assert(processMemoryLimit <= uint.MaxValue,
>>> "Trying to set processMemoryLimit too high for a 32 bit
>>> platform");
>>> ji.basicLimits32.LimitFlags |= LimitFlags.LimitProcessMemory;
>>> ji.extendedLimits32.ProcessMemoryLimit =
>>> (uint)processMemoryLimit;
>>> return ji;
>>> },
>>> ji =>
>>> {
>>> ji.basicLimits64.LimitFlags |=
>>> LimitFlags.LimitProcessMemory;
>>> ji.extendedLimits64.ProcessMemoryLimit = processMemoryLimit;
>>> return ji;
>>> });
>>> }
>>>
>>> /// <summary>
>>> /// change something about the job
>>> /// </summary>
>>> private static void ChangeJob(
>>> Func<JobObjectInfo,JobObjectInfo> alter32,
>>> Func<JobObjectInfo, JobObjectInfo> alter64)
>>> {
>>> JobObjectInfo jobObjectInfo;
>>> IntPtr currentJob = IntPtr.Zero;
>>> bool result;
>>> int returnLength;
>>>
>>> if (Is32Bit)
>>> {
>>> result = WinAPI.QueryInformationJobObject(
>>> currentJobHandle,
>>> JobObjectInfoClass.ExtendedLimitInformation,
>>> out jobObjectInfo,
>>> Marshal.SizeOf(typeof(ExtendedLimits32)),
>>> out returnLength);
>>>
>>> if (!result)
>>> {
>>> int error = Marshal.GetLastWin32Error();
>>> throw new ApplicationException("Failed calling
>>> QueryInformationJobObject, error = " + error);
>>> }
>>>
>>> Trace.Assert(
>>> returnLength == Marshal.SizeOf(typeof(ExtendedLimits32)),
>>> "QueryInformationJobObject returned " + returnLength + " bytes
>>> instead of expected "
>>> + Marshal.SizeOf(typeof(ExtendedLimits32)));
>>> jobObjectInfo = alter32(jobObjectInfo);
>>>
>>> result = WinAPI.SetInformationJobObject(
>>> currentJobHandle,
>>> JobObjectInfoClass.ExtendedLimitInformation,
>>> ref jobObjectInfo,
>>> Marshal.SizeOf(typeof(ExtendedLimits32)));
>>>
>>> if (!result)
>>> {
>>> int error = Marshal.GetLastWin32Error();
>>> var hresult = Marshal.GetHRForLastWin32Error();
>>> throw new ApplicationException("Failed calling
>>> SetInformationJobObject, error = " + error
>>> +" hresult = "+ hresult);
>>> }
>>> }
>>> else
>>> {
>>> result = WinAPI.QueryInformationJobObject(
>>> currentJobHandle,
>>> JobObjectInfoClass.ExtendedLimitInformation,
>>> out jobObjectInfo,
>>> Marshal.SizeOf(typeof(ExtendedLimits64)),
>>> out returnLength);
>>>
>>> if (!result)
>>> {
>>> int error = Marshal.GetLastWin32Error();
>>> throw new ApplicationException("Failed calling
>>> QueryInformationJobObject, error = " + error);
>>> }
>>>
>>> Trace.Assert(
>>> returnLength == Marshal.SizeOf(typeof(ExtendedLimits64)),
>>> "QueryInformationJobObject returned " + returnLength + " bytes
>>> instead of expected "
>>> + Marshal.SizeOf(typeof(ExtendedLimits64)));
>>>
>>> jobObjectInfo = alter64(jobObjectInfo);
>>>
>>> result = WinAPI.SetInformationJobObject(
>>> currentJobHandle,
>>> JobObjectInfoClass.ExtendedLimitInformation,
>>> ref jobObjectInfo,
>>> Marshal.SizeOf(typeof(ExtendedLimits64)));
>>>
>>> if (!result)
>>> {
>>> int error = Marshal.GetLastWin32Error();
>>> throw new ApplicationException("Failed calling
>>> SetInformationJobObject, error = " + error);
>>> }
>>> }
>>> }
>>> #endregion
>>>
>>> #region specific utility methods
>>>
>>> /// <summary>
>>> /// limits the memory usage of this process (and any children) to a
>>> fixed value
>>> /// Also locks the processor affinity of all child processes to the
>>> same as the current process
>>> /// </summary>
>>> /// <param name="jobMemoryLimit">set to a non zero value in bytes to
>>> limit usage</param>
>>> public static void StandardJobLimits(
>>> ulong jobMemoryLimit)
>>> {
>>> if (IsCurrentProcessMemberOfAnyJob())
>>> throw new InvalidOperationException("this process is already
>>> under the control of a job object!");
>>> CreateNewJobForCurrentProcess();
>>> SetJobMemoryLimit(jobMemoryLimit);
>>> LinkAffinityToCurrent();
>>> }
>>>
>>> /// <summary>
>>> /// limits the memory usage of this process (and any children) to a
>>> fixed value
>>> /// </summary>
>>> /// <param name="jobMemoryLimit">set to a non zero value in bytes to
>>> limit usage</param>
>>> public static void SetJobMemoryLimit(
>>> ulong jobMemoryLimit)
>>> {
>>> if (jobMemoryLimit > 0)
>>> {
>>> ChangeJob(
>>> ji =>
>>> {
>>> ji.basicLimits32.LimitFlags |= LimitFlags.LimitJobMemory;
>>> ji.extendedLimits32.JobMemoryLimit = (uint)jobMemoryLimit;
>>> return ji;
>>> },
>>> ji =>
>>> {
>>> ji.basicLimits64.LimitFlags |= LimitFlags.LimitJobMemory;
>>> ji.extendedLimits64.JobMemoryLimit = jobMemoryLimit;
>>> return ji;
>>> });
>>> }
>>> }
>>>
>>> /// <summary>
>>> /// locks the processor affinity of all child processes to the same
>>> as the current process
>>> /// </summary>
>>> public static void LinkAffinityToCurrent()
>>> {
>>> ChangeJob(
>>> ji =>
>>> {
>>> ji.basicLimits32.LimitFlags |= LimitFlags.LimitAffinity;
>>> ji.basicLimits32.Affinity =
>>> Process.GetCurrentProcess().ProcessorAffinity;
>>> return ji;
>>> },
>>> ji =>
>>> {
>>> ji.basicLimits64.LimitFlags |= LimitFlags.LimitAffinity;
>>> ji.basicLimits64.Affinity =
>>> System.Diagnostics.Process.GetCurrentProcess().ProcessorAffinity;
>>> return ji;
>>> });
>>> }
>>> #endregion
>>> }
>>> }
>>>
>>>
>>> -----Original Message-----
>>> From: condor-users-bounces@xxxxxxxxxxx
>>> [mailto:condor-users-bounces@xxxxxxxxxxx] On Behalf Of Matthew Farrellee
>>> Sent: 24 June 2009 22:26
>>> To: Condor-Users Mail List
>>> Subject: Re: [Condor-users] Condor and processor affinity
>>>
>>> Ian Stokes-Rees wrote:
>>>> There were some posts at the start of the year from Ian Chesal and Matt
>>>> Hope about setting processor affinity in jobs. Can anyone say if there
>>>> is some way to get Condor to do this automatically now? And in any
>>>> case, can anyone comment on whether this is still important? My
>>>> understanding was that kernel scheduling should handle this pretty
>>>> well.
>>>>
>>>> Ian
>>> http://www.cs.wisc.edu/condor/manual/v7.3/3_3Configuration.html#param:EnforceCpuAffinity
>>>
>>> Kernel scheduling won't keep you from using all cores on a node if you
>>> decide to fork a few times.
>>>
>>> Best,
>>>
>>>
>>> matt
>>> _______________________________________________
>>> Condor-users mailing list
>>> To unsubscribe, send a message to condor-users-request@xxxxxxxxxxx with
>>> a
>>> subject: Unsubscribe
>>> You can also unsubscribe by visiting
>>> https://lists.cs.wisc.edu/mailman/listinfo/condor-users
>>>
>>> The archives can be found at:
>>> https://lists.cs.wisc.edu/archive/condor-users/
>>>
>>> ----
>>> Gloucester Research Limited believes the information provided herein is
>>> reliable. While every care has been taken to ensure accuracy, the
>>> information is furnished to the recipients with no warranty as to the
>>> completeness and accuracy of its contents and on condition that any
>>> errors or omissions shall not be made the basis for any claim, demand or
>>> cause for action.
>>> The information in this email is intended only for the named recipient.
>>> If you are not the intended recipient please notify us immediately and
>>> do not copy, distribute or take action based on this e-mail.
>>> All messages sent to and from this email address will be logged by
>>> Gloucester Research Ltd and are subject to archival storage, monitoring,
>>> review and disclosure.
>>> Gloucester Research Limited, 5th Floor, Whittington House, 19-30 Alfred
>>> Place, London WC1E 7EA.
>>> Gloucester Research Limited is a company registered in England and Wales
>>> with company number 04267560.
>>> ----
>>>
>>> _______________________________________________
>>> Condor-users mailing list
>>> To unsubscribe, send a message to condor-users-request@xxxxxxxxxxx with
>>> a
>>> subject: Unsubscribe
>>> You can also unsubscribe by visiting
>>> https://lists.cs.wisc.edu/mailman/listinfo/condor-users
>>>
>>> The archives can be found at:
>>> https://lists.cs.wisc.edu/archive/condor-users/
>>
>
>