// bslmt_threadattributes.h -*-C++-*- // ---------------------------------------------------------------------------- // NOTICE // // This component is not up to date with current BDE coding standards, and // should not be used as an example for new development. // ---------------------------------------------------------------------------- #ifndef INCLUDED_BSLMT_THREADATTRIBUTES #define INCLUDED_BSLMT_THREADATTRIBUTES #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a description of the attributes of a thread. // //@CLASSES: // bslmt::ThreadAttributes: description of the attributes of a thread // //@SEE_ALSO: bslmt_threadutil, bslmt_configuration // //@DESCRIPTION: This component provides a simply constrained (value-semantic) // attribute class, 'bslmt::ThreadAttributes', for describing attributes of a // thread in a platform-independent way. // // The default values and constraints for the attributes provided by // 'bslmt::ThreadAttributes' are listed in the following two tables: //.. // Name Type Default // ------------------ --------------------- ---------------------- // detachedState enum DetachedState e_CREATE_JOINABLE // stackSize int e_UNSET_STACK_SIZE // guardSize int e_UNSET_GUARD_SIZE // inheritSchedule bool 'true' // schedulingPolicy enum SchedulingPolicy e_SCHED_DEFAULT // schedulingPriority int e_UNSET_PRIORITY // threadName bsl::string "" // // Name Constraint // --------- --------------------------------------------------- // stackSize 'e_UNSET_STACK_SIZE == stackSize || 0 <= stackSize' // guardSize 'e_UNSET_GUARD_SIZE == guardSize || 0 <= guardSize' //.. // ///'detachedState' Attribute ///- - - - - - - - - - - - - // The 'detachedState' attribute indicates whether an associated thread should // be created in a joinable or detached state, through the enum values // 'e_CREATE_JOINABLE' and 'e_CREATE_DETACHED', respectively. A thread in the // joinable state will have its exit status maintained after thread // termination. Any thread can join with a joinable thread (see // 'bslmt_threadutil'), in which case the joining thread will block, waiting // for the joined thread's execution to complete, after which the joined // thread's termination status will be reported back to the joining thread, and // its resources reclaimed. A thread in a detached state will have its // resources claimed at thread termination, and cannot be joined. Note that a // joinable thread can be made detached after it is created, but not vice // versa. // ///'stackSize' Attribute ///- - - - - - - - - - - // The 'stackSize' attribute indicates the size, in bytes, of the stack that // should be provided to a newly created thread. If the stack size is // 'e_UNSET_STACK_SIZE' then a created thread will be provided a default stack // size (see 'bslmt_configuration'). The 'stackSize' attribute should be // interpreted to mean that a created thread can safely define an automatic // variable of the configured 'stackSize' bytes in its thread-entry function. // Note that, on some platforms, an adjusted value derived from the 'stackSize' // attribute may be supplied to the underlying representation by the thread // creation function. // ///'guardSize' Attribute ///- - - - - - - - - - - // The 'guardSize' attribute indicates the size of the memory region to provide // past the end of a created thread's stack to protect against stack overflows. // If a thread's stack pointer overflows into a guard area, the task will // receive an error (e.g., a signal). If 'guardSize' is 'e_UNSET_GUARD_SIZE', // then a created thread will be provided with a default native guard size (see // 'bslmt_configuration'). Note that the interpretation of 'guardSize' may // vary among platforms, and the value may be adjusted up (e.g., by rounding up // to a multiple of page size) or ignored entirely (e.g., the Windows platform // does not support this attribute). // ///'inheritSchedule' Attribute ///- - - - - - - - - - - - - - // The 'inheritSchedule' attribute, if 'true', indicates that a created // thread's 'schedulingPolicy' and 'schedulingPriority' attributes should be // taken from its parent thread and the configured values of those thread // attributes should be ignored. If 'inheritSchedule' is 'false', then the // 'schedulingPolicy' and 'schedulingPriority' attribute values should be used // to configure a thread. See 'bslmt_threadutil' for information about support // for this attribute. // ///'schedulingPolicy' Attribute /// - - - - - - - - - - - - - - // The 'schedulingPolicy' attribute indicates the policy that should be used to // schedule the created thread for execution. Typically clients should use the // default platform supplied scheduling policy, which is indicated by the // 'e_SCHED_DEFAULT' value. The alternative scheduling policies, // 'e_THREAD_FIFO' and 'e_SCHED_RR', are "real-time" scheduling policies, and // may not be available unless the task is run with the appropriate privileges. // 'e_SCHED_FIFO' indicates a thread should run until it either yields or is // interrupted by a thread of higher priority. 'e_SCHED_RR' is the same as // 'e_SCHED_FIFO', except that the created thread may be interrupted by a ready // thread of equal priority after a finite time-slice. This attribute is // ignored unless 'inheritSchedule' is 'false'. See 'bslmt_threadutil' for // information about support for this attribute. // ///'schedulingPriority' Attribute /// - - - - - - - - - - - - - - - // The 'schedulingPriority' attribute is a platform specific value whose valid // values range from the minimum to the maximum value for the associated // 'schedulingPolicy', with higher numbers indicating a more urgent priority. // Functions to obtain the minimum and maximum values are in this component and // 'bslmt_threadutil'. This attribute is ignored unless 'inheritSchedule' is // 'false'. See 'bslmt_threadutil' for information about support for this // attribute. // ///'threadName' Attribute /// - - - - - - - - - - - // The 'threadName' attribute indicates the name the thread is to have. Thread // names show up in debuggers on some platforms, and are unsupported on others. // Thread names have unlimited lengths in a thread attributes object, but the // thread names actually supported by specific platforms may have limited // length, depending upon the platform, so thread names may be truncated when // assigned to the actual thread. At this time, only Linux and Darwin support // thread names, and there is a maximum thread name length of 15 on both of // those platforms. // ///Fluent Interface ///------------------ // 'bslmt::ThreadAttributes' provides manipulators that return a non-'const' // reference to the object so that setting individual attributes can be // "chained" into a single expression statement, or that attributes can be // "built" in place as a function argument. For example: //.. // bslmt::ThreadUtil::Handle handle; // // int status = bslmt::ThreadUtil::create( // &handle, // bslmt::ThreadAttributes().setThreadName("myName") // .setInheritSchedule(true), // myThreadFunction, // &myThreadArgument); //.. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Creating and Modifying Thread Attributes Objects ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // In this example we will demonstrate creating and configuring a // 'bslmt::ThreadAttributes' object, then using it with a hypothetical // thread-creation function. Finally we show how a thread creation function // might interpret those attributes for the underlying operating system. // // First we forward declare a routine that we will use to create a thread: //.. // void myThreadCreate(int *threadHandle, // const bslmt::ThreadAttributes& attributes, // void (*function)()); // // Spawn a thread having properties described by the specified // // 'attributes' and that runs the specified 'function', and assign a // // handle referring to the spawned thread to the specified // // '*threadHandle'. //.. // Then, we declare two routines that will return the minimum and maximum // thread priority given a scheduling policy. Note that similar methods exist // in 'bslmt_threadutil'. //.. // int myMinPriority(bslmt::ThreadAttributes::SchedulingPolicy policy); // int myMaxPriority(bslmt::ThreadAttributes::SchedulingPolicy policy); //.. // Next we define a function that we will use as our thread entry point. This // function declares a single variable on the stack of predetermined size. //.. // enum { k_BUFFER_SIZE = 128 * 1024 }; // // void myThreadFunction() // { // int bufferLocal[k_BUFFER_SIZE]; // // // Perform some calculation that involves no subroutine calls or // // additional automatic variables. // } //.. // Then, we define our main function, in which we demonstrate configuring a // 'bslmt::ThreadAttributes' object describing the properties a thread we will // create. //.. // void testMain() // { //.. // Next, we create a thread attributes object, 'attributes', and set its // 'stackSize' attribute to a value large enough to accommodate the // 'BUFFER_SIZE' buffer used by 'myThreadFunction'. Note that we use // 'BUFFER_SIZE' as an illustration; in practice, it is difficult or impossible // to gauge the exact amount of stack size required for a typical thread, and // the value supplied should be a reasonable *upper* bound on the anticipated // requirement. //.. // bslmt::ThreadAttributes attributes; // attributes.setStackSize(k_BUFFER_SIZE); //.. // Then, we set the 'detachedState' property to 'e_CREATE_DETACHED', indicating // that the thread will not be joinable, and its resources will be reclaimed // upon termination. //.. // attributes.setDetachedState( // bslmt::ThreadAttributes::e_CREATE_DETACHED); //.. // Now, we create a thread, using the attributes configured above: //.. // int handle; // myThreadCreate(&handle, attributes, &myThreadFunction); // } //.. // Finally, we define the thread creation function, and show how a thread // attributes object might be interpreted by it: //.. // void myThreadCreate(int *threadHandle, // const bslmt::ThreadAttributes& attributes, // void (*function)()) // // Spawn a thread with properties described by the specified // // 'attributes', running the specified 'function', and assign a handle // // referring to the spawned thread to the specified '*threadHandle'. // { // int stackSize = attributes.stackSize(); // if (bslmt::ThreadAttributes::e_UNSET_STACK_SIZE == stackSize) { // stackSize = bslmt::Configuration::defaultThreadStackSize(); // } // // // Add a "fudge factor" to 'stackSize' to ensure that the client can // // declare an object of 'stackSize' bytes on the stack safely. // // stackSize += 8192; // // int guardSize = attributes.guardSize(); // if (bslmt::ThreadAttributes::e_UNSET_GUARD_SIZE == guardSize) { // guardSize = bslmt::Configuration::nativeDefaultThreadGuardSize(); // } // // int policy = attributes.schedulingPolicy(); // int priority = attributes.schedulingPriority(); // // // the following is pseudo-code for actually creating the thread // /* // if (bslmt::ThreadAttributes::e_UNSET_PRIORITY == priority) { // priority = operatingSystemDefaultPriority(policy); // } // // operatingSystemThreadCreate(threadHandle, // stackSize, // guardSize, // attributes.inheritSchedule(), // policy, // priority, // attributes.detachedState() // function); // */ // } //.. // Notice that a new value derived from the 'stackSize' attribute is used so // that the meaning of the attribute is platform neutral. #include <bslscm_version.h> #include <bslma_allocator.h> #include <bslma_usesbslmaallocator.h> #include <bslmf_assert.h> #include <bslmf_nestedtraitdeclaration.h> #include <bsls_assert.h> #include <bsls_platform.h> #include <bsl_c_limits.h> #include <bsl_iosfwd.h> #include <bsl_string.h> namespace BloombergLP { namespace bslmt { // ====================== // class ThreadAttributes // ====================== class ThreadAttributes { // This simply constrained (value-semantic) attribute class characterizes a // collection of thread attribute values. See the Attributes section under // @DESCRIPTION in the component-level documentation. // // This class: //: o supports a complete set of *value* *semantic* operations //: o except for 'bdex' serialization //: o is *exception-neutral* //: o is *alias-safe* //: o is 'const' *thread-safe* // For terminology see 'bsldoc_glossary'. public: // PUBLIC TYPES enum DetachedState { // This enumeration provides two values used to distinguish among a // joinable thread and a non-joinable (detached) thread. e_CREATE_JOINABLE = 0, // create a joinable thread e_CREATE_DETACHED = 1 // create a non-joinable thread #ifndef BDE_OMIT_INTERNAL_DEPRECATED , BCEMT_CREATE_JOINABLE = e_CREATE_JOINABLE , BCEMT_CREATE_DETACHED = e_CREATE_DETACHED , CREATE_JOINABLE = e_CREATE_JOINABLE , CREATE_DETACHED = e_CREATE_DETACHED #endif // BDE_OMIT_INTERNAL_DEPRECATED }; enum SchedulingPolicy { // This enumeration provides values used to distinguish between // different thread scheduling policies. e_SCHED_OTHER = 0, // unspecified, OS-dependent scheduling // policy e_SCHED_FIFO = 1, // first-in-first-out scheduling policy e_SCHED_RR = 2, // round-robin scheduling policy e_SCHED_DEFAULT = 3 // default OS scheduling policy, usually // equivalent to 'e_SCHED_OTHER' #ifndef BDE_OMIT_INTERNAL_DEPRECATED , BCEMT_SCHED_OTHER = e_SCHED_OTHER , BCEMT_SCHED_FIFO = e_SCHED_FIFO , BCEMT_SCHED_RR = e_SCHED_RR , BCEMT_SCHED_DEFAULT = e_SCHED_DEFAULT #endif // BDE_OMIT_INTERNAL_DEPRECATED }; enum { // The following constants indicate that the 'stackSize', 'guardSize', // and 'schedulingPriority' attributes, respectively, are unspecified // and the thread creation routine is use platform-specific defaults. // These attributes are initialized to these values when a thread // attributes object is default constructed. e_UNSET_STACK_SIZE = -1, e_UNSET_GUARD_SIZE = -1, e_UNSET_PRIORITY = INT_MIN, e_SCHED_MIN = e_SCHED_OTHER, e_SCHED_MAX = e_SCHED_DEFAULT #ifndef BDE_OMIT_INTERNAL_DEPRECATED , BCEMT_UNSET_STACK_SIZE = e_UNSET_STACK_SIZE , BCEMT_UNSET_GUARD_SIZE = e_UNSET_GUARD_SIZE , BCEMT_UNSET_PRIORITY = e_UNSET_PRIORITY , BCEMT_SCHED_MIN = e_SCHED_MIN , BCEMT_SCHED_MAX = e_SCHED_MAX #endif // BDE_OMIT_INTERNAL_DEPRECATED }; private: // DATA DetachedState d_detachedState; // whether the thread is detached // or joinable int d_guardSize; // size of guard area provided // beyond the end of the configured // thread's stack bool d_inheritScheduleFlag; // whether the thread inherits its // scheduling policy & priority // from its parent thread SchedulingPolicy d_schedulingPolicy; // policy for scheduling thread // execution int d_schedulingPriority; // thread priority (higher numbers // indicate more urgency) int d_stackSize; // size of the thread's stack bsl::string d_threadName; // name of the thread public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(ThreadAttributes, bslma::UsesBslmaAllocator); // CREATORS ThreadAttributes(); explicit ThreadAttributes(bslma::Allocator *basicAllocator); // Create a 'ThreadAttributes' object having the (default) attribute // values: //: o 'detachedState() == e_CREATE_JOINABLE' //: o 'guardSize() == e_UNSET_GUARD_SIZE' //: o 'inheritSchedule() == true' //: o 'schedulingPolicy() == e_SCHED_DEFAULT' //: o 'schedulingPriority() == e_UNSET_PRIORITY' //: o 'stackSize() == e_UNSET_STACK_SIZE' //: o 'threadName() == ""' // Optionally specify a 'basicAllocator' used to supply memory. If // 'basicAllocator' is 0, the currently installed default allocator is // used. ThreadAttributes(const ThreadAttributes& original, bslma::Allocator *basicAllocator = 0); // Create a 'ThreadAttributes' object having the same value as the // specified 'original' object. Optionally specify a 'basicAllocator' // used to supply memory. If 'basicAllocator' is 0, the currently // installed default allocator is used. // MANIPULATORS ThreadAttributes& operator=(const ThreadAttributes& rhs); // Assign to this object the value of the specified 'rhs' object, and // return a reference providing modifiable access to this object. // MANIPULATORS ThreadAttributes& setDetachedState(DetachedState value); // Set the 'detachedState' attribute of this object to the specified // 'value'. Return a non-'const' reference to this object (see also // {Fluent Interface}). A value of 'e_CREATE_JOINABLE' (the default) // indicates that a thread must be joined to clean up its resources // after it terminates; a value of 'e_CREATE_DETACHED' (the only other // legal value) indicates that the resources will be cleaned up // automatically upon thread termination, and that the thread must not // be joined. ThreadAttributes& setGuardSize(int value); // Set the 'guardSize' attribute of this object to the specified // 'value' (in bytes). Return a non-'const' reference to this object // (see also {Fluent Interface}). 'e_UNSET_GUARD_SIZE == guardSize' is // intended to indicate that the default value as defined by the // platform is to be used. This default value is typically the size of // one or two pages (see 'bslmt_configuration'). The behavior is // undefined unless 'e_UNSET_GUARD_SIZE == guardSize' or // 'guardSize >= 0'. ThreadAttributes& setInheritSchedule(bool value); // Set the 'inheritSchedule' attribute of this object to the specified // 'value'. Return a non-'const' reference to this object (see also // {Fluent Interface}). A value of 'false' for the inherit schedule // attribute indicates that a thread should *not* inherit the // scheduling policy and priority of the thread that created it and // instead should use the respective values supplied by this object; // whereas a value of 'true' indicates that the thread *should* inherit // these attributes and ignore the respective values in this object. // See 'bslmt_threadutil' for information about support for this // attribute. ThreadAttributes& setSchedulingPolicy(SchedulingPolicy value); // Set the value of the 'schedulingPolicy' attribute of this object to // the specified 'value'. Return a non-'const' reference to this // object (see also {Fluent Interface}). This attribute is ignored // unless 'inheritSchedule' is 'false'. See 'bslmt_threadutil' for // information about this attribute. ThreadAttributes& setSchedulingPriority(int value); // Set the 'schedulingPriority' attribute of this object to the // specified 'value'. Return a non-'const' reference to this object // (see also {Fluent Interface}). This attribute is ignored unless // 'inheritSchedule()' is 'false'. Higher values of 'value' signify // more urgent priorities. Note that the valid range of priorities // depends upon the platform and 'schedulingPolicy' attribute, and the // minimum and maximum priority values are determined by methods in // 'bslmt_threadutil'. See 'bslmt_threadutil' for information about // this attribute. ThreadAttributes& setStackSize(int value); // Set the 'stackSize' attribute of this object to the specified // 'value'. Return a non-'const' reference to this object (see also // {Fluent Interface}). If 'stackSize' is 'e_UNSET_STACK_SIZE', thread // creation should use the default stack size value provided by // 'bslmt_configuration'. The behavior is undefined unless // 'e_UNSET_STACK_SIZE == stackSize' or '0 <= stackSize'. ThreadAttributes& setThreadName(const bslstl::StringRef& value); // Set the 'threadName' attribute of this object to the specified // 'value'. Return a non-'const' reference to this object (see also // {Fluent Interface}). // ACCESSORS DetachedState detachedState() const; // Return the value of the 'detachedState' attribute of this object. A // value of 'e_CREATE_JOINABLE' indicates that a thread must be joined // after it terminates to clean up its resources; a value of // 'e_CREATE_DETACHED' (the only other legal value) indicates that the // resources will be cleaned up automatically upon thread termination, // and that the thread must not be joined. int guardSize() const; // Return the value of the 'guardSize' attribute of this object. The // value 'e_UNSET_GUARD_SIZE == guardSize' is intended to indicate that // the default value as defined by the platform (which is typically the // size of one or two pages) should be obtained from // 'bslmt_configuration' and used. bool inheritSchedule() const; // Return the value of the 'inheritSchedule' attribute of this object. // A value of 'false' for the inherit schedule attribute indicates that // a thread should *not* inherit the scheduling policy and priority of // the thread that created it and instead should use the respective // values supplied by this object; whereas a value of 'true' indicates // that the thread *should* inherit these attributes and ignore the // respective values in this object. See 'bslmt_threadutil' for // information about support for this attribute. bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; // Format this object to the specified output 'stream' at the (absolute // value of) the optionally specified indentation 'level' and return a // reference to 'stream'. If 'level' is specified, optionally specify // 'spacesPerLevel', the number of spaces per indentation level for // this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. SchedulingPolicy schedulingPolicy() const; // Return the value of the 'schedulingPolicy' attribute of this object. // This attribute is ignored unless 'inheritSchedule' is 'false'. See // 'bslmt_threadutil' for information about this attribute. int schedulingPriority() const; // Return the value of the 'schedulingPriority' attribute of this // object. This attribute is ignored unless 'inheritSchedule()' is // 'false'. Higher values of 'value' signify more urgent priorities. // Note that the valid range of priorities depends upon the platform // and 'schedulingPolicy' attribute, and the minimum and maximum // priority values are determined by methods in 'bslmt_threadutil'. // See 'bslmt_threadutil' for information about this attribute. int stackSize() const; // Return the value of the 'stackSize' attribute of this object. If // 'stackSize' is 'e_UNSET_STACK_SIZE', thread creation should use the // default stack size value provided by 'bslmt_configuration'. bslstl::StringRef threadName() const; // Return the 'threadName' attribute of this object. Note that the // returned string reference will be invalidated if 'setThreadName' is // subsequently called on this object. // Aspects bslma::Allocator *allocator() const; // Return the allocator used by this object to supply memory. }; // FREE OPERATORS bool operator==(const ThreadAttributes& lhs, const ThreadAttributes& rhs); // Return 'true' if the specified 'lhs' and 'rhs' objects have the same // value, and 'false' otherwise. Two 'ThreadAttributes' objects have the // same value if the corresponding values of their 'detachedState', // 'guardSize', 'inheritSchedule', 'schedulingPolicy', // 'schedulingPriority', and 'stackSize' attributes are the same. bool operator!=(const ThreadAttributes& lhs, const ThreadAttributes& rhs); // Return 'true' if the specified 'lhs' and 'rhs' objects do not have the // same value, and 'false' otherwise. Two 'baltzo::LocalTimeDescriptor' // objects do not have the same value if the corresponding values of their // 'detachedState', 'guardSize', 'inheritSchedule', 'schedulingPolicy', // 'schedulingPriority', and 'stackSize' attributes are not the same. // FREE OPERATORS bsl::ostream& operator<<(bsl::ostream& stream, const ThreadAttributes& object); // Write the value of the specified 'object' object to the specified output // 'stream' in a single-line format, and return a reference to 'stream'. // If 'stream' is not valid on entry, this operation has no effect. Note // that this human-readable format is not fully specified, can change // without notice, and is logically equivalent to: //.. // print(stream, 0, -1); //.. // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ---------------------- // class ThreadAttributes // ---------------------- // MANIPULATORS inline ThreadAttributes& ThreadAttributes::setDetachedState( ThreadAttributes::DetachedState value) { BSLS_ASSERT_SAFE(e_CREATE_DETACHED == value || e_CREATE_JOINABLE == value); d_detachedState = value; return *this; } inline ThreadAttributes& ThreadAttributes::setGuardSize(int value) { BSLMF_ASSERT(-1 == e_UNSET_GUARD_SIZE); BSLS_ASSERT_SAFE(-1 <= value); d_guardSize = value; return *this; } inline ThreadAttributes& ThreadAttributes::setInheritSchedule(bool value) { d_inheritScheduleFlag = value; return *this; } inline ThreadAttributes& ThreadAttributes::setSchedulingPolicy( ThreadAttributes::SchedulingPolicy value) { BSLS_ASSERT_SAFE(e_SCHED_MIN <= (int) value); BSLS_ASSERT_SAFE( (int) value <= e_SCHED_MAX); d_schedulingPolicy = value; return *this; } inline ThreadAttributes& ThreadAttributes::setSchedulingPriority(int value) { d_schedulingPriority = value; return *this; } inline ThreadAttributes& ThreadAttributes::setStackSize(int value) { BSLMF_ASSERT(-1 == e_UNSET_STACK_SIZE); BSLS_ASSERT_SAFE(-1 <= value); d_stackSize = value; return *this; } inline ThreadAttributes& ThreadAttributes::setThreadName( const bslstl::StringRef& value) { d_threadName.assign(value); return *this; } // ACCESSORS inline ThreadAttributes::DetachedState ThreadAttributes::detachedState() const { return d_detachedState; } inline int ThreadAttributes::guardSize() const { return d_guardSize; } inline bool ThreadAttributes::inheritSchedule() const { return d_inheritScheduleFlag; } inline ThreadAttributes::SchedulingPolicy ThreadAttributes::schedulingPolicy() const { return d_schedulingPolicy; } inline int ThreadAttributes::schedulingPriority() const { return d_schedulingPriority; } inline int ThreadAttributes::stackSize() const { return d_stackSize; } inline bslstl::StringRef ThreadAttributes::threadName() const { return d_threadName; } // Aspects inline bslma::Allocator *ThreadAttributes::allocator() const { return d_threadName.get_allocator().mechanism(); } // FREE OPERATORS inline bsl::ostream& operator<<(bsl::ostream& stream, const ThreadAttributes& object) { return object.print(stream, 0, -1); } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2020 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------