/* * (c) Copyright, Real-Time Innovations, 2003-2024. * All rights reserved. * * No duplications, whole or partial, manual or electronic, may be made * without express written permission. Any such copies, or * revisions thereof, must display this notice unaltered. * This code contains trade secrets of Real-Time Innovations, Inc. */ #ifndef osapi_thread_h #define osapi_thread_h #include "osapi/osapi_ntptime.h" #include "osapi/osapi_dll.h" #include "log/log_common.h" #include "osapi/osapi_cpu.h" #ifdef __cplusplus extern "C" { #endif /** @internal \file * \brief thread related utility */ /** @internal \defgroup RTIOsapiThreadClass RTIOsapiThread * \ingroup RTIOsapiModule * * \brief OS independent encapsulation of an application thread. */ struct RTIOsapiThread; /** @internal * \defgroup RTIOsapiJoinableThreadClass RTIOsapiThread * \ingroup RTIOsapiModule * * \brief A class that inherits from RTIOsapiThread and has special * capabilities: * - Ability to stop the execution of the thread and delete it. * A JoinableThread will create a semaphore to synchronize the deletion of the * thread. When the user calls RTIOsapiJoinableThread_stopAndDelete, the * semaphore will wait until the thead finish its spawn method. * - The thread has a worker associated. * The method RTIOsapiJoinableThread_new will create a worker and associate it * to the thread. * * More info in confluence: Engineering aka R&D-> R&D Teams -> General Purpose * Products -> Developer knowledge Base -> Concurrency -> Thread -> * JoinableThread */ struct RTIOsapiJoinableThread; /** @internal \ingroup RTIOsapiThreadClass Use only the default options the OS gives you. */ #define RTI_OSAPI_THREAD_OPTION_DEFAULT 0x00 /** @internal \ingroup RTIOsapiThreadClass Support floating point. */ #define RTI_OSAPI_THREAD_OPTION_FLOATING_POINT 0x01 /** @internal \ingroup RTIOsapiThreadClass This thread can do standard io. */ #define RTI_OSAPI_THREAD_OPTION_STDIO 0x02 /** @internal \ingroup RTIOsapiThreadClass This thread will run in real-time priority mode. */ #define RTI_OSAPI_THREAD_OPTION_REALTIME_PRIORITY 0x08 /** @internal \ingroup RTIOsapiThreadClass Insist on the specified priority and fail if OS doesn't like it. */ #define RTI_OSAPI_THREAD_OPTION_PRIORITY_ENFORCE 0x10 /** @internal \ingroup RTIOsapiThreadClass Set the flag to be able to asynchronously cancel thread. */ #define RTI_OSAPI_THREAD_OPTION_CANCEL_ASYNCHRONOUS 0x20 /** @internal \ingroup RTIOsapiThreadClass * * TESTING ONLY. Skip the creation of the Context Tss in the * onSpawned method. This option is used to test automatic TSS * cleanup. This option lets us create threads in tests more * closely to how a user may create threads in their * applications (e.g. using calls directly to pthread_create * instead of through our wrapper APIs). Our wrapper APIs make * sure that state is cleaned up properly when they are used, * but we want to test that the state is also cleaned up when * our wrappers are not used. */ #define RTI_OSAPI_THREAD_OPTION_SKIP_CONTEXT_CREATION 0x40 /** @internal \ingroup RTIOsapiThreadClass Indicates to create the thread with the OS default stack size. If not supported, will use the platform default. */ #define RTI_OSAPI_THREAD_STACK_SIZE_OS_DEFAULT (-1) #if defined(RTI_VXWORKS) typedef enum { RTI_OSAPI_THREAD_PRIORITY_HIGH = 68, RTI_OSAPI_THREAD_PRIORITY_ABOVE_NORMAL = 71, RTI_OSAPI_THREAD_PRIORITY_NORMAL = 100, RTI_OSAPI_THREAD_PRIORITY_BELOW_NORMAL = 110, RTI_OSAPI_THREAD_PRIORITY_LOW = 120 } RTIOsapiThreadPriority; #define RTI_OSAPI_THREAD_PRIORITY_DEFAULT RTI_OSAPI_THREAD_PRIORITY_NORMAL #define RTI_OSAPI_THREAD_STACK_SIZE_DEFAULT (40 * 1024) #elif defined(RTI_PSOS) typedef enum { RTI_OSAPI_THREAD_PRIORITY_HIGH = 150, RTI_OSAPI_THREAD_PRIORITY_ABOVE_NORMAL = 130, RTI_OSAPI_THREAD_PRIORITY_NORMAL = 100, RTI_OSAPI_THREAD_PRIORITY_BELOW_NORMAL = 90, RTI_OSAPI_THREAD_PRIORITY_LOW = 80 } RTIOsapiThreadPriority; #define RTI_OSAPI_THREAD_PRIORITY_DEFAULT RTI_OSAPI_THREAD_PRIORITY_NORMAL #define RTI_OSAPI_THREAD_STACK_SIZE_DEFAULT (16 * 1024) #elif defined(RTI_LYNX) typedef enum { RTI_OSAPI_THREAD_PRIORITY_HIGH = 32, RTI_OSAPI_THREAD_PRIORITY_ABOVE_NORMAL = 29, RTI_OSAPI_THREAD_PRIORITY_NORMAL = 17, RTI_OSAPI_THREAD_PRIORITY_BELOW_NORMAL = 13, RTI_OSAPI_THREAD_PRIORITY_LOW = 10 } RTIOsapiThreadPriority; #define RTI_OSAPI_THREAD_PRIORITY_DEFAULT RTI_OSAPI_THREAD_PRIORITY_NORMAL #define RTI_OSAPI_THREAD_STACK_SIZE_DEFAULT (64 * 1024) #elif defined(RTI_NETOS) typedef enum { RTI_OSAPI_THREAD_PRIORITY_HIGH = 6, RTI_OSAPI_THREAD_PRIORITY_ABOVE_NORMAL = 9, RTI_OSAPI_THREAD_PRIORITY_NORMAL = 15, RTI_OSAPI_THREAD_PRIORITY_BELOW_NORMAL = 20, RTI_OSAPI_THREAD_PRIORITY_LOW = 22 } RTIOsapiThreadPriority; #define RTI_OSAPI_THREAD_PRIORITY_DEFAULT RTI_OSAPI_THREAD_PRIORITY_NORMAL #define RTI_OSAPI_THREAD_STACK_SIZE_DEFAULT (16 * 1024) #elif defined(RTI_WIN32) typedef enum { RTI_OSAPI_THREAD_PRIORITY_HIGH = 3, RTI_OSAPI_THREAD_PRIORITY_ABOVE_NORMAL = 2, RTI_OSAPI_THREAD_PRIORITY_NORMAL = 0, RTI_OSAPI_THREAD_PRIORITY_BELOW_NORMAL = -2, RTI_OSAPI_THREAD_PRIORITY_LOW = -3 } RTIOsapiThreadPriority; #define RTI_OSAPI_THREAD_PRIORITY_DEFAULT RTI_OSAPI_THREAD_PRIORITY_NORMAL #define RTI_OSAPI_THREAD_STACK_SIZE_DEFAULT \ (RTI_OSAPI_THREAD_STACK_SIZE_OS_DEFAULT) #elif defined(RTI_INTIME) typedef enum { RTI_OSAPI_THREAD_PRIORITY_HIGH = 3, RTI_OSAPI_THREAD_PRIORITY_ABOVE_NORMAL = 2, RTI_OSAPI_THREAD_PRIORITY_NORMAL = 0, RTI_OSAPI_THREAD_PRIORITY_BELOW_NORMAL = -2, RTI_OSAPI_THREAD_PRIORITY_LOW = -3 } RTIOsapiThreadPriority; #define RTI_OSAPI_THREAD_PRIORITY_DEFAULT RTI_OSAPI_THREAD_PRIORITY_NORMAL #define RTI_OSAPI_THREAD_STACK_SIZE_DEFAULT (192 * 1024) #elif defined(RTI_WINCE) typedef enum { RTI_OSAPI_THREAD_PRIORITY_HIGH = 249, RTI_OSAPI_THREAD_PRIORITY_ABOVE_NORMAL = 250, RTI_OSAPI_THREAD_PRIORITY_NORMAL = 251, RTI_OSAPI_THREAD_PRIORITY_BELOW_NORMAL = 252, RTI_OSAPI_THREAD_PRIORITY_LOW = 253 } RTIOsapiThreadPriority; #define RTI_OSAPI_THREAD_PRIORITY_DEFAULT RTI_OSAPI_THREAD_PRIORITY_NORMAL #define RTI_OSAPI_THREAD_STACK_SIZE_DEFAULT (0) #elif defined(RTI_QNX) typedef enum { RTI_OSAPI_THREAD_PRIORITY_HIGH = 14, RTI_OSAPI_THREAD_PRIORITY_ABOVE_NORMAL = 12, RTI_OSAPI_THREAD_PRIORITY_NORMAL = 10, RTI_OSAPI_THREAD_PRIORITY_BELOW_NORMAL = 8, RTI_OSAPI_THREAD_PRIORITY_LOW = 6 } RTIOsapiThreadPriority; #define RTI_OSAPI_THREAD_PRIORITY_DEFAULT RTI_OSAPI_THREAD_PRIORITY_NORMAL #define RTI_OSAPI_THREAD_STACK_SIZE_DEFAULT (64 * 1024) #elif defined(RTI_INTY) typedef enum { RTI_OSAPI_THREAD_PRIORITY_HIGH = 120, RTI_OSAPI_THREAD_PRIORITY_ABOVE_NORMAL = 100, RTI_OSAPI_THREAD_PRIORITY_NORMAL = 90, RTI_OSAPI_THREAD_PRIORITY_BELOW_NORMAL = 80, RTI_OSAPI_THREAD_PRIORITY_LOW = 60 } RTIOsapiThreadPriority; #define RTI_OSAPI_THREAD_PRIORITY_DEFAULT 16 #define RTI_OSAPI_THREAD_STACK_SIZE_DEFAULT (64 * 1024) #elif defined(RTI_AIX) typedef enum { RTI_OSAPI_THREAD_PRIORITY_HIGH = -9999999, RTI_OSAPI_THREAD_PRIORITY_ABOVE_NORMAL = -9999999, RTI_OSAPI_THREAD_PRIORITY_NORMAL = -9999999, RTI_OSAPI_THREAD_PRIORITY_BELOW_NORMAL = -9999999, RTI_OSAPI_THREAD_PRIORITY_LOW = -9999999 } RTIOsapiThreadPriority; #define RTI_OSAPI_THREAD_PRIORITY_DEFAULT RTI_OSAPI_THREAD_PRIORITY_NORMAL /* * The default stack size on 32 bit AIX is too small, the default for 64 bit * is 192KB, which is enough. Set the default high enough. */ #define RTI_OSAPI_THREAD_STACK_SIZE_DEFAULT (192 * 1024) #else typedef enum { RTI_OSAPI_THREAD_PRIORITY_HIGH = -9999999, RTI_OSAPI_THREAD_PRIORITY_ABOVE_NORMAL = -9999999, RTI_OSAPI_THREAD_PRIORITY_NORMAL = -9999999, RTI_OSAPI_THREAD_PRIORITY_BELOW_NORMAL = -9999999, RTI_OSAPI_THREAD_PRIORITY_LOW = -9999999 } RTIOsapiThreadPriority; #define RTI_OSAPI_THREAD_PRIORITY_DEFAULT RTI_OSAPI_THREAD_PRIORITY_NORMAL #define RTI_OSAPI_THREAD_STACK_SIZE_DEFAULT \ (RTI_OSAPI_THREAD_STACK_SIZE_OS_DEFAULT) #endif /* setting of default thread property */ /** @internal \ingroup RTIOsapiThreadClass * @brief Default thread name prefix for transport threads. */ #define NDDS_TRANSPORT_THREAD_NAME_PREFIX_DEFAULT "rTr#####" typedef void RTIOsapiThreadTssFactory; /** @internal \ingroup RTIOsapiThreadClass * @brief Creates the factory that provides keys for * thread-local storage. * * The factory is intended to act as a singleton. * It's definition is opaque and implementation-dependent. * This function is not thread safe. */ extern RTIOsapiDllExport RTIOsapiThreadTssFactory * RTIOsapiThread_createTssFactory(void); /** @internal \ingroup RTIOsapiThreadClass * @brief Deletes the factory. * This function is not thread safe. */ extern RTIOsapiDllExport void RTIOsapiThread_deleteTssFactory( RTIOsapiThreadTssFactory *factory); /** @internal \ingroup RTIOsapiThreadClass * * @brief Enables or disables automatic tss cleanup on platforms * that support it, depending on the value passed in for * enable. * * @see RTIOsapiThread_createKeyWithDtor */ extern RTIOsapiDllExport void RTIOsapiThread_enableTssDestructors( RTIBool enable); /** @internal \ingroup RTIOsapiThreadClass * @brief Returns true if automatic tss destructor support has * been enabled. Windows and POSIX APIs support providing * a destructor when a TSS key is created that will be * called when the thread exits so that the TSS * associated with that thread can be cleaned up. * * @see RTIOsapiThread_createKeyWithDtor * @see RTIOsapiThread_enableTssDestructors */ extern RTIOsapiDllExport RTIBool RTIOsapiThread_tssDestructorsAreEnabled(void); #if defined(RTI_POSIX_THREADS) #include #define RTI_OSAPI_THREAD_INVALID_TSS_KEY (PTHREAD_KEYS_MAX + 1) #elif defined (RTI_WIN32) #define RTI_OSAPI_THREAD_INVALID_TSS_KEY TLS_OUT_OF_INDEXES #elif defined(RTI_RTP) #define RTI_OSAPI_THREAD_INVALID_TSS_KEY ERROR #else #define RTI_OSAPI_THREAD_INVALID_TSS_KEY 0xFFFFFFFF #endif /** @internal \ingroup RTIOsapiThreadClass * @brief Returns an invalid TSS key value. This value is * different depending on the platform, so instead of * defining a single constant we have this function * * @see RTIOsapiThread_isTssKeyValid */ extern RTIOsapiDllExport RTI_UINT32 RTIOsapiThread_getInvalidTssKey(void); /** @internal \ingroup RTIOsapiThreadClass * @brief Returns true if the tss key value is in the valid * range of values. This range varies per platform * * @see RTIOsapiThread_getInvalidTssKey */ extern RTIOsapiDllExport RTIBool RTIOsapiThread_isTssKeyValid(RTI_UINT32 key); /** @internal \ingroup RTIOsapiThreadClass * * @brief Function prototype for a destructor that can be * associated to a TSS key when it is created. * * Some platforms support associating a destructor callback to a * TSS key in the form of this function prototype. * * @param tssValue When a thread exits and the destructor is * called for a TSS key slot, tssValue is the value in the tss * slot that this destructor is associated with. */ #if defined(RTI_WIN32) && !defined(RTI_64BIT) /* * On 32-bit Windows the destructor callback function is defined with the * __stdcall calling convention, which is not the default. The default is * __cdecl. We must use this same calling convention when defining our * callback prototype or else there will be compiler errors about mismatched * function types. Casting from a function that is declared with __cdecl to * one defined with __stdcall will lead to stack corruption. */ #define RTI_OSAPI_THREAD_TSS_DTOR_CALLING_CONVENTION __stdcall #else #define RTI_OSAPI_THREAD_TSS_DTOR_CALLING_CONVENTION #endif typedef void(RTI_OSAPI_THREAD_TSS_DTOR_CALLING_CONVENTION *RTIOsapiThreadTssDesctructorFnc)(void *tssValue); /** @internal \ingroup RTIOsapiThreadClass * @brief create key with a destructor. * * @param key \b Out. The key created will be returned here. * @param tssFactory \b In. The singleton created by * RTIOsapiThread_createTssFactory * @param destructor \b In. The destructor to be called when the * thread exits to cleanup the data that is pointed at by * key. Not all platforms support automatically calling a * destructor. See RTIOsapiThread_supportsTssDestructor. * * The destructor must take the following into account: * * - On platforms which support pthreads the following is * true: * - When a key is deleted, the destructor will NO * LONGER be called on any outstanding threads that * may have non-NULL values in the key slot which is * being deleted. This mean that the memory will be * leaked if it is not tracked and cleaned up * elsewhere. * - When a thread exits, the TSS slot is set to * NULL, and then the destructor is called, passing * in the previous (non-NULL) value to the * destructor. This means that calling getTss will * return a NULL value and setting the TSS to NULL * within the destructor is not needed. * * - On Windows, when a key is deleted, the destructor * for all outstanding threads with non-NULL values * stored at that key ARE called within the context of * the same thread that is deleting the key. The * implications of this are: * - Any lock that is taken within the destructor * must be reentrant if the code path that is * deleting the key is also taking that lock. * - The destructor is not called within the * context of the thread whose TSS is being * deleted, so calling APIs to get or set TSS in * the destructor will be getting and setting TSS * within the thread that is deleting the key, * not within the thread that is having its TSS * cleaned up. * * The best practices therefore when deleting a key that * has an associated destructor is to: * 1. Cache the key value. * 2. Set the key to an invalid value * 3. Delete the key using the cached value * 4. In the destructor: * - Check for an invalid key value and if the * key is invalid, exit without cleaning up * anything, therefore leaving the code path * that is deleting the key to clean up all * resources that may have been stored in TSS * for all threads. * - Do not call getTss or setTss -- since you * can't be sure what thread the destructor is * called in * - Make sure all locks that are used are * reentrant on Windows * * @return RTI_TRUE on success, RTI_FALSE on failure */ extern RTIOsapiDllExport RTIBool RTIOsapiThread_createKeyWithDtor( RTI_UINT32 *key, RTIOsapiThreadTssFactory *factory, RTIOsapiThreadTssDesctructorFnc destructor); /** @internal \ingroup RTIOsapiThreadClass * @brief create key. * * @param key \b Out. The key created will be returned here. * @param tssFactory \b In. The singleton created by * RTIOsapiThread_createTssFactory * @return RTI_TRUE on success, RTI_FALSE on failure */ extern RTIOsapiDllExport RTIBool RTIOsapiThread_createKey(RTI_UINT32 *key, RTIOsapiThreadTssFactory *tssFactory); /** @internal \ingroup RTIOsapiThreadClass * @brief set thread specific storage. * * @param key \b In. The key of the storage. * @param value \b In. The param put into the storage. * @return RTI_TRUE on success, RTI_FALSE on failure */ extern RTIOsapiDllExport RTIBool RTIOsapiThread_setTss(RTI_UINT32 key, const void *value); /** @internal \ingroup RTIOsapiThreadClass * @brief get thread specific storage. * * @param key \b In. The key of the storage. * @return The value in the storage if success. NULL on failure. */ extern RTIOsapiDllExport void *RTIOsapiThread_getTss(RTI_UINT32 key); /** @internal \ingroup RTIOsapiThreadClass * @brief Get thread specific storage Integer value. * * @param key \b In. The key of the storage. * @return The value in the storage as Integer, if success. 0 on failure. */ extern RTIOsapiDllExport RTI_INT32 RTIOsapiThread_getTssAsInteger(RTI_UINT32 key); /** @internal \ingroup RTIOsapiThreadClass * @brief set thread specific storage for an Integer value. * * @param key \b In. The key of the storage. * @param value \b In. The Integer value to put into the storage. * @return RTI_TRUE on success, RTI_FALSE on failure */ extern RTIOsapiDllExport RTIBool RTIOsapiThread_setTssAsInteger(RTI_UINT32 key, RTI_INT32 value); /** @internal \ingroup RTIOsapiThreadClass * @brief delete key. * * @param key \b In. The key to be deleted. * @param tssFactory \b In. The singleton created by * RTIOsapiThread_createTssFactory * @return RTI_TRUE on success, RTI_FALSE on failure */ extern RTIOsapiDllExport RTIBool RTIOsapiThread_deleteKey(RTIOsapiThreadTssFactory *tssFactory, RTI_UINT32 key); /** @internal \ingroup RTIOsapiThreadClass * * @brief Static method to suspend current thread, sleep for specified NTP time. * * This call suspends the current thread for the specified duration. * Note that the granularity, and minimum sleep time are OS dependant. * * - \b On \b VxWorks, this function calls taskDelay(), * hence the granularity and the minimum sleep time are a * single clock tick (as reported by sysClockRateGet()). * - \b On \b pSOS, this function calls tm_wkafter(); the granularity is * determined by the clock-tick rate. * - \b On \b Unix, this function calls either poll() or select(). * In fact it may call them multiple times if poll()/select() * return prematurely woken by a signal. RTIOsapiThread_sleep() keeps * track of the total time slept using gettimeofday() to ensure * the specified usec have elapsed. * - \b On \b Win32, use Sleep(), which has a different granularity * on different windows OSes, but is generally poorer than 10 ms. * * \b Example: * * To sleep for 1.5 seconds, * \verbatim * RTINtpTime time; * RTINtpTime_packFromMillisec(time, 1, 500); * RTIOsapiThread_sleep(&time); * \endverbatim * * @param time The amount of time to sleep using RTITime. If NULL * (infinite time), sleep forever (on UNIX a very long time). * If Zero time, it causes a at least a context switch. * @return RTI_FALSE if error occurred (e.g., if thread is locked on * VxWorks) otherwise, return RTI_TRUE. * * @mtsafety NOT safe in the first call. Safe subsequently. */ extern RTIOsapiDllExport RTIBool RTIOsapiThread_sleep(const struct RTINtpTime *timeIn); /** @internal \ingroup RTIOsapiThreadClass * * @brief Static method to suspend current thread using an active wait. * * This method is usually used in combination with * RTIClock_getSpinPerMicrosecond. */ extern RTIOsapiDllExport void RTIOsapiThread_spin(RTI_UINT64 spinCount); /** @internal \ingroup RTIOsapiThreadClass * * @brief Get a thread's priority */ extern RTIOsapiDllExport int RTIOsapiThread_getPriority( struct RTIOsapiThread *me); /** @internal \ingroup RTIOsapiThreadClass * @brief log CPU affinity for a thread * * This method acts as a proxy for printing the CPU affinity for a * thread. Because affinity APIs are OS-specific, we * centralize their use so othe modules can remain agnostic. */ extern RTIOsapiDllExport void RTIOsapiThread_logCpuAffinity( const char *threadName); #if defined(RTI_CPU_AFFINITY) && defined(RTI_POSIX_THREADS) && defined(RTI_LINUX) /** @internal \ingroup RTIOsapiThreadClass * @brief get the CPU affinity for a thread. * * Only supported on platforms that support CPU affinity. */ extern RTIOsapiDllExport RTIBool RTIOsapiThread_getCpu(char *cpuBuffer); /** @internal \ingroup RTIOsapiThreadClass * @brief get the maximum number of CPUs in set. * * Only supported on platforms that support CPU affinity. */ extern RTIOsapiDllExport RTI_INT32 RTIOsapiThread_getCpuCount(void); #endif /** @internal \ingroup RTIOsapiThreadClass * * @brief Function prototype for entry point for the thread. * * Function prototype for the routine specified at thread creation * time. The new thread will start executing this function. * * @param threadParam Pointer to data that will be passed to the thread * routine. You must cast this to appropriate type to access the data. */ typedef void *(*RTIOsapiThreadOnSpawnedMethod)(void *threadParam); /** @internal \ingroup RTIOsapiThreadClass * * @brief ctor * * Creates a new thread with the specified priority and * stack. The new thread starts executing the "thread_rtn" which gets * passed the single parameter "param". * The thread is removed when the function "thread_rtn" returns. * * If a stack pointer different than NULL is provided, the thread will be * created so it uses the provided memory as stack. Otherwise, a stack with the * specified size will be created by the underlying OS. * * The function returns a newly allocated ThreadId. It is the * responsibility of the user of this method to free this structure again * with RTIOsapiThread_delete (see the example below). * * As a convenience, the CPU bitmap parameter may be NULL. This has * the same effect as passing a bitmap corresponding to the default * QoS. In these cases, the thread affinity is left to the OS to handle. * * The priority passed to RTIOsapiThread_new() is the *native* OS priority. * You can use RTIOsapiThreadClassNativePriorityGet() to get a native priority * from a system-independent logical priority. * * NOTE: By default this function does not check whether the * specified priority is in the allowed range for the OS/Mode where the * process is running. If it is not in range, you will get * whatever the OS decides to give you. To get predictable behavior, * you must specify the RTI_OSAPI_THREAD_OPTION_PRIORITY_ENFORCE flag in your * options parameter. When this option is specified, RtiTreadCreate() * will check the priority, and return NULL *without* starting * the thread if the priority is outside the allowed range. * * Hence you should *always* use RTI_OSAPI_THREAD_OPTION_PRIORITY_ENFORCE. * The only reason this is not the default is to provide backwards * compatibility. * * Note on IRIX native sprocs: * * Priorities from NDPHIMAX (30) to NDPHIMIN (39) are considered real-time * and higher than normally scheduled processes. * * You should NOT set normal priorities if don't want to degrade * what you would get if didn't try to set any priorities. * Setting a normal priority will guarantee that you get something * less than if you didn't set anything at all! * * Note on Windows: * * Windows supports 7 levels for threads (within each priority class - * there are 4 priorities classes, and all * threads within a process belong to one of these 4 classes): The actual enum * value of these macros is different on Windows, and to gain some * commonality, the THREAD_OPTION_PRIORITIES are defined as follows. (This * mapping is done during ThreadCreate, but not with ThreadPrioritySet, there * you must use native priorities) * * - RTI_OSAPI_THREAD_PRIORITY_TIME_CRITICAL - 3 * - RTI_OSAPI_THREAD_PRIORITY_HIGHEST - 2 * - RTI_OSAPI_THREAD_PRIORITY_ABOVE_NORMAL - 1 * - RTI_OSAPI_THREAD_PRIORITY_NORMAL - 0 * - RTI_OSAPI_THREAD_PRIORITY_BELOW_NORMAL - -1 * - RTI_OSAPI_THREAD_PRIORITY_LOWEST - -2 * * On Windows: * * THREAD_PRIORITY_IDLE - -3 * * \b Example: * The following provide some basic examples: * * \verbatim * struct RTIOsapiThread* tid; * tid = RTIOsapiThread_new("WelcomeThread", 100, * RTI_OSAPI_THREAD_OPTION_PRIORITY_ENFORCE, * 1024, NULL, PrintMessage, "Hello world", NULL); * RTIOsapiThread_delete(tid); * \endverbatim * * @param name The name of the thread. * @param priority The operating system specific priority. * @param options Thread options. * @param stack Thread's stack. If NULL the OS will provide a stack of * stackSize * @param stackSize Stack size * @param cpuBitmap CPUs the thread can run on. May be NULL, which imposes * no restrictions. * @param thread_rtn The starting location of this new thread. * * @return On failure, this function returns NULL. On success, this function * returns a handle to a new thread, which you should use later in * dtor. * * @see RTIOsapiThread_delete */ extern RTIOsapiDllExport struct RTIOsapiThread *RTIOsapiThread_newWithStack( const char *name, int priority, int options, void *stack, int stackSize, struct RTIOsapiCpuBitmap *cpuBitmap, RTIOsapiThreadOnSpawnedMethod thread_rtn, void *threadParam); /** @internal \ingroup RTIOsapiThreadClass * * @brief Initializes a thread whose stack is managed by the underlying OS * */ extern RTIOsapiDllExport RTIBool RTIOsapiThread_initialize( struct RTIOsapiThread *me, const char *name, int priority, int options, int stackSize, struct RTIOsapiCpuBitmap *cpuBitmap, RTIOsapiThreadOnSpawnedMethod thread_rtn, void *threadParam); /** @internal \ingroup RTIOsapiThreadClass * * @brief Creates a thread whose stack is managed by the underlying OS has the * specified size. * * @see RTIOsapiThread_newWithStack */ extern RTIOsapiDllExport struct RTIOsapiThread *RTIOsapiThread_new( const char *name, int priority, int options, int stackSize, struct RTIOsapiCpuBitmap *cpuBitmap, RTIOsapiThreadOnSpawnedMethod thread_rtn, void *threadParam); /** @internal \ingroup RTIOsapiThreadClass * @brief Delete a thread. * Frees the memory associates with the ThreadId. * By default, the thread will be joined. * * @param tid A handle to the thread to delete. */ extern RTIOsapiDllExport void RTIOsapiThread_delete(struct RTIOsapiThread *me); /** @internal \ingroup RTIOsapiThreadClass * @brief Delete a thread. * Frees the memory associates with the ThreadId. * By default, the thread will be joined. * * @param tid A handle to the thread to delete. * @param me \b In. joinThread. Call pthread_join. It should be true for the * thread created in osapi.1.0. It can be false for thread created by * the native Java API (new Thread()). */ extern RTIOsapiDllExport void RTIOsapiThread_deleteEx( struct RTIOsapiThread *me, RTIBool joinThread); #if defined(RTI_WIN32) || defined(RTI_WINCE) || defined(RTI_VXWORKS) \ || defined(RTI_INTIME) /** @internal \ingroup RTIOsapiThreadClass * * @brief Terminate the thread. (Windows and VxWorks OS only) * * Wrapper for windows TerminateThread call, required since thread handles are * OS specific, and cannot be "generalized". Higher layers should confine * themselves to the use of RTIOsapiThread structures, and utilize the OSAPI * layer to perform system calls. * * Wrapper for vxworks taskDelete call. * * @param struct RTIOsapiThread* me. */ extern RTIOsapiDllExport void RTIOsapiThread_terminateThread( struct RTIOsapiThread *me); #endif /** @internal \ingroup RTIOsapiThreadClass * * @brief Get the thread from which this method is called. * * This method returns a new copy of this thread object; the client is * responsible for deleting it when it's no longer needed. Deleting the * thread object does not affect the actually running thread of execution. * * @return The thread object corresponding to the calling thread. * * @author rbw */ extern RTIOsapiDllExport struct RTIOsapiThread *RTIOsapiThread_getCurrentThread( void); /** @internal \ingroup RTIOsapiThreadClass * * @brief Get the threadID from which this method is called. * * @return 32-bit value corresponding to the calling thread, or zero on failure. * * @author as */ extern RTIOsapiDllExport RTI_UINT64 RTIOsapiThread_getCurrentThreadID(void); /** @internal \ingroup RTIOsapiThreadClass * * @brief Gets the native priority for the thread. * * RTI priority range is from normalMin to normalMax, which is nominally * 0 to 255 with 255 being the highest priority. * * Because not all OS's have 256 priority levels there may be a many to * one mapping of RTI priorities to native priorities. * * The mapping is linear at this time and will change depending on the * operation mode that you are running and requesting. */ extern RTIOsapiDllExport RTIBool RTIOsapiThread_getNativePriorityFromNormal( int *nativePriority, int normalPriority, int normalMin, int normalMax, int options); /** @internal \ingroup RTIOsapiThreadClass * * @brief Gets the normalized priority for the thread. * * RTI priority range is from normalMin to normalMax, which is nominally * 0 to 255 with 255 being the highest priority. * * Because not all OS's have 256 priority levels there may be a many to * one mapping of RTI priorities to native priorities. * * The mapping is linear at this time and will change depending on the * operation mode that you are running and requesting. */ extern RTIOsapiDllExport RTIBool RTIOsapiThread_getNormalPriorityFromNative( int *normalPriority, int nativePriority, int normalMin, int normalMax, int options); /** @internal \ingroup RTIOsapiThreadClass * * @brief Checks whether managed stack is supported by the current platform. * * Managed stack is supported by certain platforms only. For instance, some * POSIX implementations support this via pthread_attr_setstack. * * @return RTI_TRUE if supported. */ extern RTIOsapiDllExport RTIBool RTIOsapiThread_isManagedStackSupported(void); /*--------------------- RTIOsapiJoinableThread -------------------------------*/ /** @internal \ingroup RTIOsapiThreadClass * Default blocking timeout 20 sec. */ #define RTI_OSAPI_THREAD_DEFAULT_BLOCKING_TIMEOUT 20000 /** @internal \ingroup RTIOsapiThreadClass * Infinite blocking timeout. */ #define RTI_OSAPI_THREAD_INFINITE_BLOCKING_TIMEOUT RTI_UINT32_MAX /** @internal \defgroup RTIOsapiJoinableThreadClass RTIOsapiThread * \ingroup RTIOsapiModule * * \brief A regular delete call that will block timeoutMillisec the thread. * It removes the resources associate to the thread. * */ extern RTIOsapiDllExport RTIBool RTIOsapiJoinableThread_stopAndDelete( struct RTIOsapiJoinableThread *self, RTI_UINT32 timeoutMillisec); /** @internal \defgroup RTIOsapiJoinableThreadClass RTIOsapiThread * \ingroup RTIOsapiModule * * \brief Creates a controlled thread. Parameters are the same than a regular * OSAPI thread. * */ extern RTIOsapiDllExport struct RTIOsapiJoinableThread * RTIOsapiJoinableThread_new( const char *name, int priority, int options, int stackSize, struct RTIOsapiCpuBitmap *cpuBitmap, RTIOsapiThreadOnSpawnedMethod thread_rtn, void *threadParam); /** @internal \ingroup RTIOsapiModule * * @brief Get a thread's priority */ extern RTIOsapiDllExport int RTIOsapiJoinableThread_getPriority( struct RTIOsapiJoinableThread *me); /** @internal * @brief Get the name of the thread. * * @return the name of the thread. * The caller of this function is responsible for freeing the string. */ extern RTIOsapiDllExport char *RTIOsapiThread_getName(void); /** @internal * @brief Set the name of the thread * * @param name \b In. Name of the thread * * @return If there is an error returns the returnCode. Otherwise, 0 */ extern RTIOsapiDllExport int RTIOsapiThread_setName(const char *name); #if ((defined(RTI_LINUX) && defined(__GLIBC__) \ && ((__GLIBC__ > 2) || (__GLIBC__ == 2 && (__GLIBC_MINOR__ >= 12)))) \ || (defined(RTI_DARWIN) && defined(__MAC_OS_X_VERSION_MAX_ALLOWED) \ && (__MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_6)) \ || defined(RTI_QNX) || defined(RTI_WIN32) \ || (defined(RTI_IOS) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 30200))) \ && defined(RTI_CPU_AFFINITY) #define RTI_OSAPI_SET_THREAD_NAME_SUPPORTED 1 #else #define RTI_OSAPI_SET_THREAD_NAME_SUPPORTED 0 #endif #if RTI_OSAPI_SET_THREAD_NAME_SUPPORTED && defined(RTI_POSIX_THREADS) #define RTI_OSAPI_GET_THREAD_NAME_SUPPORTED 1 #else #define RTI_OSAPI_GET_THREAD_NAME_SUPPORTED 0 #endif /** @internal * For all the platforms: * We limit the thread name length to 16 characters, * including the null byte ('\0'). * This limit comes from Linux, that is the more restrictive architecture. * We use the same limit in all the platforms for consistency. */ #define RTI_OSAPI_THREAD_NAME_MAX_SIZE 16 /** @internal * Thread name prefix represents the concatenation of: * 'r' + Module + participantIdentification + '\0'. * For example the Transport prefix thread: * With domainID (111) and participantId (22) * "rTr11122" */ #define RTI_OSAPI_THREAD_NAME_PREFIX_MAX_SIZE 9 /** @internal * Thread participant identification: * 5 characters + '\0'. */ #define RTI_OSAPI_THREAD_PARTICIPANT_ID_MAX_SIZE 6 /** @internal * Thread module abbreviation: * 3 characters + '\0'. */ #define RTI_OSAPI_THREAD_MODULE_MAX_SIZE 4 /** @internal * Thread task type: * 3 characters + '\0'. */ #define RTI_OSAPI_THREAD_TASK_TYPE_MAX_SIZE 4 /** @internal * Thread custom name, not fitting a pattern: * 9 characters + '\0'. */ #define RTI_OSAPI_THREAD_CUSTOM_NAME_MAX_SIZE 10 /** @internal * Thread transport name, such as "TCP4": * 4 characters + '\0'. */ #define RTI_OSAPI_THREAD_TRANSPORT_NAME_MAX_SIZE 5 /** @internal The task type for the event thread */ #define RTI_OSAPI_EVENT_THREAD_TASK_TYPE "Evt" /** @internal The task type for the receive thread */ #define RTI_OSAPI_RECEIVE_THREAD_TASK_TYPE "Rcv" /** @internal The task type for the local credential thread */ #define RTI_OSAPI_LOCAL_CREDENTIAL_THREAD_TASK_TYPE "LCr" /** @internal \ingroup RTIOsapiThreadClass * \brief Disables the support to log the backTrace. * * This function is not thread safe */ extern RTIOsapiDllExport void RTIOsapiThread_disableBacktraceSupport(void); /** @internal \ingroup RTIOsapiThreadClass * \brief Enables the support to log the backTrace. * * This function is not thread safe * * @param tssFactory \b In. TSS Factory to cache the backtrace per thread. * * @return RTI_TRUE on success. * RTI_FALSE on failure enabling the log backtrace support. */ extern RTIOsapiDllExport RTIBool RTIOsapiThread_enableBacktraceSupport(RTIOsapiThreadTssFactory *tssFactory); struct RTIOsapiThreadBacktraceNode; /** @internal \ingroup RTIOsapiThreadClass * * @brief Clean cached backtrace in current thread's TSS. * * @param finalizeBacktraceNode \b In. The first time a thread caches a * backtrace, in addition to the backtrace itself, we allocate some additional * resources. When finalizeBacktraceNode is set to RTI_TRUE, this function will * release both the cached backtrace and those additional resources. If * finalizeBacktraceNode is set to RTI_FALSE, this function will delete the * cached backtrace, but it will not release these additional resources (which * will be deleted upon DomainParticipantGlobals destruction). * * @param node \b In. If passed in as non-NULL, this is the node * that is finalized. When passed in as NULL, the * function attempts to get the node from TSS. It is * passed in as non-NULL when called from the TSS * destructor on those platforms that support * automatic tss destruction upon thread exit. */ extern RTIOsapiDllExport void RTIOsapiThread_finalizeCachedBacktrace( RTIBool finalizeBacktraceNode, struct RTIOsapiThreadBacktraceNode *node); /** @internal \ingroup RTIOsapiThreadClass * \brief Install a signal handler * * This function is not thread safe * * @return RTI_TRUE on success or RTI_FALSE on failure. */ extern RTIOsapiDllExport RTIBool RTIOsapiThread_installSigsegvHandler(void); /** @internal \ingroup RTIOsapiThreadClass * @brief Log the stack trace of the current thread. * * @param index \b In. The first element of the stack to log. * @param detailLevel \b In. Only for RTI_LINUX. Define the level of detail of * the backtrace. * @param handlingSigsegv \b In. Whether we are handling a SIGSEGV. If we are, * we cannot call malloc because it is not signal safe. */ extern RTIOsapiDllExport void RTIOsapiThread_logBacktrace( int index, RTILogBacktraceDetailLevel detailLevel, int handlingSigsegv); /** @internal \ingroup RTIOsapiThreadClass * @brief Add function name to the queue of Function History per worker * * @param pointerFuncName \b In. Function name. */ extern RTIOsapiDllExport void RTIOsapiThread_addFunctionToDebugInfo( void *pointerFuncName); /** @internal * - RTI_OSAPI_BACKTRACE_SUPPORTED means that the backtrace feature is * supported. * - RTI_BACKTRACE_DISABLED_BY_DEFAULT means that the backtrace feature is * disabled by default. When disabled by default, it can only be enabled by * setting the logPrintFormat bit RTI_LOG_PRINT_BIT_FORCE_BACKTRACE. * - RTI_OSAPI_BACKTRACE_TEST_SUPPORTED means that the backtrace feature is * suported and it is enabled by default. */ #if (defined(RTI_DARWIN) || defined(RTI_WIN32) \ || (defined(RTI_LINUX) \ && ENABLE_FACE_COMPLIANCE == FACE_COMPLIANCE_LEVEL_NONE)) \ && !defined(RTI_ANDROID) #define RTI_OSAPI_BACKTRACE_SUPPORTED #ifndef RTI_BACKTRACE_DISABLED_BY_DEFAULT /* Backtrace unit tests are supported */ #define RTI_OSAPI_BACKTRACE_TEST_SUPPORTED #endif #else /* * If backtrace is not supported: * support FunctionHistory feature in debug mode. * FunctionHistory can be supported also by setting * RTI_FUNCTION_HISTORY_SUPPORTED in the systemIncludes * of the makefile of the platform, like: * "systemIncludes += -DRTI_FUNCTION_HISTORY_SUPPORTED" */ #ifdef RTI_PRECONDITION_TEST #define RTI_FUNCTION_HISTORY_SUPPORTED #endif /* RTI_PRECONDITION_TEST */ #endif #if ((defined(RTI_DARWIN) || defined(RTI_LINUX) || defined(RTI_WIN32)) \ && !defined(RTI_IOS) && !defined(RTI_ANDROID)) #define RTI_OSAPI_SIGNAL_HANDLER_SUPPORTED 1 #endif /** @internal \ingroup RTIOsapiThreadClass * Function pointer to destroy a worker. */ typedef void (*RTIOsapiThread_destroyWorkerMethod)(void *worker); extern RTIOsapiDllVariable RTIOsapiThread_destroyWorkerMethod RTIOsapiThread_destroyWorker; /** @internal \ingroup RTIOsapiThreadClass * Function pointer to associate a worker to the current thread. */ typedef RTIBool (*RTIOsapiThread_associateWorkerMethod)(void *worker); extern RTIOsapiDllVariable RTIOsapiThread_associateWorkerMethod RTIOsapiThread_associateWorker; /** @internal \ingroup RTIOsapiThreadClass * Function pointer to create a worker with a name. */ typedef void *(*RTIOsapiThread_createWorkerMethod)(const char *name); extern RTIOsapiDllVariable RTIOsapiThread_createWorkerMethod RTIOsapiThread_createWorker; /** @internal \ingroup RTIOsapiThreadClass * @brief Create a thread name in the first parameter based on the other * parameters * * @param[in,out] threadName Calling functions must provide a string allocated * for 16 characters. The output is a thread consisting of 15 characters and a * null terminator. * @param[in] threadPrefix A string of at most 8 characters that consists of a * module and an identifier such as a participant ID, topic name, task, or * user-supplied name. May not be null. Will be truncated at 8 characters if * necessary. * @param[in] threadIndex Disregard if equal to -1. * @param[in] taskType A string of 3 characters such as "Evt", "AWs", "Ctr", * "Rcv", "Dtb", "Dsp", "Wri", "Log", "ITr", "ABF", "TQP", "Rea", or "Pub". May * not be null. */ extern RTIOsapiDllExport void RTIOsapiThread_createThreadName( char *threadName, const char *threadPrefix, int threadIndex, const char *taskType); /** @internal \ingroup RTIOsapiThreadClass * @brief Create a name for a participant thread in the first parameter based on * the other parameters * * @param[in,out] threadName Calling functions must provide a string allocated * for 16 characters. The output is a thread consisting of 15 characters and a * null terminator. * @param[in] module A string of at most three characters identifying the * product such as "rTR", "rCo", "rRS", "rPS", "rSe", or "RDI". May not be * null. * @param[in] participantId A string of at most 5 characters--may not be null. * @param[in] threadIndex Disregard if equal to -1. * @param[in] taskType A string of 3 characters such as "Evt", "AWs", "Ctr", * "Rcv", "Dtb", "Dsp", "Wri", "Log", "ITr", "ABF", "TQP", "Rea", or "Pub". May * not be null. */ extern RTIOsapiDllExport void RTIOsapiThread_createParticipantThreadName( char *threadName, const char *module, const char *participantId, int threadIndex, const char *taskType); /** @internal \ingroup RTIOsapiThreadClass * @brief Create a thread name in the first parameter based on the other * parameters * * @param[in,out] threadName Calling functions must provide a string allocated * for 16 characters. The output is a thread consisting of 15 characters and a * null terminator. * @param[in] threadPrefix A string of at most 8 characters that consists of a * module and an identifier such as a participant ID, topic name, task, or * user-supplied name. May not be null. Will be truncated at 8 characters if * necessary. * @param[in] transportName A string of at most 4 characters describing the * transport used ("TCP4"). May not be null. * @param[in] taskType A string of 3 characters such as "Evt", "AWs", "Ctr", * "Rcv", "Dtb", "Dsp", "Wri", "Log", "ITr", "ABF", "TQP", "Rea", or "Pub". May * not be null. */ extern RTIOsapiDllExport void RTIOsapiThread_createTransportThreadName( char *threadName, const char *threadPrefix, const char *transportName, const char *taskType); /** @internal \ingroup RTIOsapiThreadClass * @brief Create a thread name in the first parameter based on the other * parameters * * @param[in,out] threadName Calling functions must provide a string allocated * for 16 characters. The output is a thread consisting of 15 characters and a * null terminator. * @param[in] module A string of at most 3 characters that consists of a * module and an identifier such as a participant ID, topic name, task, or * user-supplied name. May not be null. * @param[in] customName Custom string of at most 9 characters for use in the * thread name. May not be null. Will be truncated at 9 characters if necessary. * @param[in] taskType A string of 3 characters such as "Evt", "AWs", "Ctr", * "Rcv", "Dtb", "Dsp", "Wri", "Log", "ITr", "ABF", "TQP", "Rea", or "Pub". May * not be null. */ extern RTIOsapiDllExport void RTIOsapiThread_createCustomThreadName( char *threadName, const char *module, const char *customName, const char *taskType); /** @internal * @brief Returns the thread ID of the 'self' thread object. * * This operation can be called from any threading context. Note that this is * different than RTIOsapiThread_getCurrentId(), which receives no parameter * and returns the id from the caller thread context. */ extern RTIOsapiDllExport RTI_UINT64 RTIOsapiThread_getId(struct RTIOsapiThread *self); /** @internal \ingroup RTIOsapiProcessClass * @brief Definition of the Cpu information type for a Thread */ struct RTIOsapiThreadCpuInfo { RTI_UINT64 id; struct RTINtpTime cpuTime; }; #define RTIOsapiThreadCpuInfo_INITIALIZER \ { \ 0, RTI_NTP_TIME_ZERO \ } /** @internal \ingroup RTIOsapiProcessClass * @brief Obtain information about the cpu used by the specified thread. * * @param[out] cpu_info Holder to the structure that will return the cpu info. */ extern RTIOsapiDllExport void RTIOsapiThread_getCpuInfo( struct RTIOsapiThread *self, struct RTIOsapiThreadCpuInfo *cpuInfo); #if defined(RTI_LINUX) || defined(RTI_DARWIN) || defined(RTI_WIN32) \ || defined(RTI_QNX) #define RTI_OSAPI_THREAD_CPU_INFO_SUPPORTED #endif #ifdef __cplusplus } /* extern "C" */ #endif #include "osapi/osapi_thread_impl.h" #endif /* osapi_thread_h */