int
tis_write_unlock (
tis_rwlock_t *lock);
lock
Address of the readers/writer lock.
This routine unlocks a readers/writer lock that was acquired in write access mode.Return Values If an error condition occurs, this routine returns an integer value indicating the type error. Possible return values are as follows:Upon completion of this routine, any thread waiting to acquire the lock in read access mode will have the locks granted. If no threads are waiting to acquire the lock in read access mode, then a thread waiting to acquire it in write access mode will have the lock granted.
Return | Description |
---|---|
0 | Successful completion. |
[EINVAL] | The value specified by lock is invalid. |
This appendix discusses DECthreads issues specific to Digital UNIX systems.
The Digital UNIX operating system supports multiple concurrent execution contexts within a process. DECthreads uses these kernel execution contexts to implement user threads. One important benefit of this is that user threads can run simultaneously on separate processors in a multiprocessor system. Review Section 3.1 for tips for ensuring that your application will work correctly with kernel threads and multiprocessing.
The following sections discuss points to consider when building using DECthreads.
Include one of the DECthreads header files shown in Table A-1 in your program to use the appropriate DECthreads library.
Header File | Interface |
---|---|
pthread.h | POSIX.1c routines |
tis.h | Thread-independent services routines |
Do not include more than one of these header files in your module.
Multithreaded applications are built using shared libraries. For a discussion about shared libraries, see the Digital UNIX Programmer's Guide.
Table A-2 contains the libraries supported for multithreaded programming.
libmach.so | Shared version of threads support library. Direct use of mach interfaces is not supported. |
libpthread.so | Shared version of the base pthreads package. Requires libmach.so, libexc.so, and libc.so |
libexc.so | Shared version of Digital UNIX exception support package. |
libpthreads.so | Shared version of DECthreads "legacy" package, implementing the Digital proprietary CMA (or cma) and POSIX 1003.4a/Draft 4 (or d4) interfaces. |
libc.so | Shared version of the C language run-time library ( libc.so). |
Build a multithreaded application using shared versions of libexc, libmach, libpthread, and libc as follows:
% cc -o myprog myprog.c -pthread
The ld command does not support the -pthread or -threads switch. Instead, you must list the individual libraries in the proper order.
For libraries that use only the pthread interface, use the following:
ld <...> -lpthread -lmach -lexc -lc
If using the cma or d4 interfaces, use the following:
ld <...> -lpthreads -lpthread -lmach -lexc -lc
Applications that use the Digital proprietary thread-independent services (or tis) interface should include the tis.h header file and link against the shared C run-time library (libc.so).
Under Digital UNIX Version 4.0 and later, DECthreads implements a new scheduling model, referred to as two-level scheduling. DECthreads schedules "user threads" onto kernel execution contexts (often known as "kernel threads" or "virtual processors"), just as Digital UNIX schedules processes onto the processors of a multiprocessing machine.
A user thread is executed on a kernel thread until it blocks or exhausts its timeslice quantum. Then, DECthreads schedules a new user thread to run. While DECthreads is scheduling user threads onto kernel threads, the Digital UNIX kernel is independently scheduling those kernel threads to run on physical processors. The term two-level scheduling refers to this relationship.
This division allows most thread scheduling to take place completely in user mode, without the intervention of the kernel. Since a thread context switch does not involve any privileged information, it can be done much more efficiently in user mode.
The key to making the two-level scheduling model work is efficient two-way communication between DECthreads and the Digital UNIX kernel. When a thread blocks in the kernel, the DECthreads scheduler is notified so that it can schedule another thread to take advantage of the idle kernel thread. This mechanism is sometimes referred to as an upcall, and is inspired by the original University of Washington research on Scheduler Activations. (See Scheduler Activations: Effective Kernel Support for the User-Level Management of Parallelism by Anderson, Bershad, Lazowska, and Levy; ACM Operating Systems Review Volume 25, Number 5, Proceedings of the Thirteenth ACM Symposium on Operating Systems Principles, October 13-16, 1991).
Digital UNIX kernel threads are created as they are needed by the application. The number of kernel threads that DECthreads creates is limited by normal Digital UNIX configuration limits regarding user and system thread creation. Normally, however, DECthreads creates one kernel thread for each actual processor on the system and the kernel creates an additional kernel thread on behalf of the process for bookkeeping operations.
DECthreads does not delete these kernel threads or let them terminate. Kernel threads not currently needed are retained in an idle state until they are needed again. When the process terminates, all kernel threads in the process are reclaimed by the kernel.
The DECthreads scheduler can schedule any user thread onto any kernel thread. Therefore, a user thread can run on different kernel threads at different times. Normally, this should pose no problem. However, for example, the kernel thread ID as reported by the dbx or Ladebug debuggers can change at any time.
DECthreads supports Digital UNIX real-time scheduling. This allows you to set the scheduling policy and priority of threads. By default, threads are created using process contention scope. This means that the full range of POSIX.1c scheduling policy and priority is available. However, threads running in process contention scope do not preempt lower-priority threads in another process. For example, a thread in process contention scope with SCHED_FIFO policy and PRI_FIFO_MAX priority will not preempt a thread in another process running with SCHED_FIFO and PRI_FIFO_MIN.
System contention scope means that each thread created by the program has a direct and unique binding to one kernel execution context. A system contention scope thread competes against all threads in the system and will preempt any thread with lower priority. For this reason, the priority range of threads in system contention scope is restricted unless running with root privilege.
Specifically, a thread with SCHED_FIFO policy cannot run at a priority higher than 18 without privilege, since doing so could lock out all other users on the system until the thread blocked. Threads at any other scheduling policy (including SCHED_RR) can run at priority 19 because they are subject to periodic timeslicing by the system. For more information, see the Digital UNIX Realtime Programming Guide.
If your program lacks necessary privileges, attempting to call the following routines for a thread in system contention scope returns the error value [EPERM]:
pthread_attr_setschedpolicy() | ( Error returned by pthread_create() at thread creation) |
pthread_attr_setschedparam() | ( Error returned by pthread_create() at thread creation) |
pthread_setschedparam() |
Prior to Digital UNIX Version 4.0, all threads used system contention scope. In Digital UNIX Version 4.0, all threads created using DECthreads are in process contention scope. In the future, the pthread_attr_setscope() function will allow the programmer to select the desired contention scope for each thread created.
Digital UNIX supports the required system cancelation points specified by the POSIX.1c standard. In addition, critical non-POSIX functions supported by Digital UNIX (such as select()) have also been defined as cancelation points.
For legacy multithreaded applications, note that threads created using the cma or d4 interfaces will not be cancelable at any system call. (Here "system call" means any function without the pthread_ prefix.) If system call cancelation is required, you must write code using the DECthreads pthread interface. None of the system calls should be called with asynchronous cancelation enabled.
For more information, see Section 2.3.7.
The following functions are cancelation points:
accept() |
recvfrom() |
The following list contains POSIX functions that are not cancelation points in this release of DECthreads but might be in a future release (as specified by the POSIX.1c standard). Please code your programs accordingly.
closedir() |
getpwnam() |
Note that appropriate non-POSIX functions that do not appear in the preceding list might become cancelation points in the future. Digital UNIX will also implement new cancelation points, as specified by future revisions of the relevant formal or consortium standard bodies.
This section discusses signal handling based on the POSIX.1c standard.
Digital UNIX Version 4.0 introduces the full POSIX.1c signal model. In previous versions, "synchronous" signals (those resulting from execution errors, such as SIGSEGV and SIGILL) could have different signal actions for each thread. Prior to Digital UNIX Version 3.2, all threads shared a common, processwide signal mask, which meant one thread could not receive a signal while another had the signal blocked.
Under Digital UNIX Version 4.0 and later, all signal actions are processwide. That is, when any thread uses sigaction or equivalent to set a signal handler, or to modify the signal action (for example, to ignore a signal), that action will affect all threads. Each thread has a private signal mask so that it can block signals without affecting the behavior of other threads.
Prior to Digital UNIX Version 4.0, asynchronous signals were processed only in the main thread. In Digital UNIX Version 4.0, any thread that doesn't have the signal masked can process the signal. To support binary compatibility, for a thread created by a cma or d4 interface routine, the thread starts with all asynchronous signals blocked.
The POSIX 1003.1c sigwait() service allows any thread to block until one of a specified set of signals is delivered. A thread can wait for any of the asynchronous signals except for SIGKILL and SIGSTOP.
For example, you can create a thread that blocks on a sigwait() routine for SIGINT, rather than handling a Ctrl/C in the normal way. This thread could then cancel other threads to cause the program to shut down the current activities.
Following are two reasons for avoiding signals:
In a multithreaded program, signal handlers cannot be used in a modular way because there is only one signal handler routine for all of the threads in an application. If two threads install different signal handlers for the signal, all threads will dispatch to the last handler when they receive the signal.
Most applications should avoid using asynchronous programming techniques in conjunction with threads. For example, techniques that rely on timer and I/O signals are usually more complicated and errorprone than simply waiting synchronously within a thread. Furthermore, most of the threads services are not supported for use in signal handlers, and most run-time library functions cannot be used reliably inside a signal handler.
Some I/O intensive code may benefit from asynchronous I/O, but these programs will generally be more difficult to write and maintain than "pure" threaded code.
A thread should not wait for a synchronous signal. This is because synchronous signals are the result of an error during the execution of a thread, and if the thread is waiting for a signal, then it is not executing. Therefore, a synchronous signal cannot occur for a particular thread while it is waiting, and the thread will wait forever.
The POSIX.1c standard requires that the thread block the signals for which it will wait before calling sigwait().
For the signals traditionally representing synchronous errors in the program, DECthreads catches the signal and converts it into an equivalent exception. This exception is then propagated up the call stack in the current thread and can be caught and handled using the normal exception catching mechanisms.
Table A-3 lists Digital UNIX signals that are reported as DECthreads exceptions by default. If any thread declares an action for one of these signals (using sigaction(2) or equivalent), no thread in the process can receive the exception.
Signal | Exception |
---|---|
SIGILL | pthread_exc_illinstr_e |
SIGIOT | pthread_exc_SIGIOT_e |
SIGEMT | pthread_exc_SIGEMT_e |
SIGFPE | pthread_exc_aritherr_e |
SIGBUS | pthread_exc_illaddr_e |
SIGSEGV | pthread_exc_illaddr_e |
SIGSYS | pthread_exc_SIGSYS_e |
SIGPIPE | pthread_exc_SIGPIPE_e |
Dynamic activation of DECthreads, or of code that depends on DECthreads, is currently not supported.
This appendix discusses DECthreads issues and restrictions specific to the OpenVMS operating system.
Under OpenVMS, DECthreads offers these application programming interfaces:
The DECthreads C language header files shown in Table B-1 provide interface definitions for DECthreads APIs.
Header File | Interface |
---|---|
pthread.h | POSIX.1c style routines |
tis.h | Digital-proprietary thread-independent services routines |
Include only one of these header files in your module.
Special compiler definitions are not required when compiling threaded applications that use the pthread interface or the tis interface.
When you link an image that calls DECthreads routines, you must link against the appropriate images listed in Table B-2.
Image | Routine Library |
---|---|
PTHREAD$RTL.EXE | POSIX.1c style interface |
CMA$TIS_SHR.EXE | Thread-independent services |
The image files PTHREAD$RTL.EXE, CMA$TIS_SHR.EXE, CMA$RTL.EXE, and CMA$LIB_SHR.EXE are included in the IMAGELIB library, making it unnecessary to specify those images (unless you are using the /NOSYSLIB switch with the linker) in a Linker options file.
When you link an image that utilizes the CMA$OPEN_LIB_SHR.EXE and CMA$OPEN_RTL.EXE images, they must be specified in a Linker options file.
DECthreads is supplied only as shareable images. It is not supplied as object libraries.
An asynchronous system trap (or AST) is an OpenVMS mechanism for reporting an asynchronous event to a process. The following are restrictions concerning the use of ASTs with DECthreads:
Dynamic activation of DECthreads (or images that depend on DECthreads) is currently not supported.
This section discusses a restriction on declaring an OpenVMS condition handler while using DECthreads exceptions and DECthreads behavior when a condition is signaled.
The following are three ways to declare an OpenVMS condition handler:
Do not declare an OpenVMS condition handler within a DECthreads TRY/ENDTRY exception block. Doing so deletes without notification any handler that exists for the current procedure. If your code declares a condition handler within the TRY/ENDTRY block, DECthreads exceptions will not be handled correctly until the next TRY statement is executed. The TRY statement restores the DECthreads condition handler.
On OpenVMS VAX, you can declare a condition handler outside of a TRY/ENDTRY block with no restrictions. If a condition handler has already been declared when you execute a TRY statement, DECthreads saves the previous handler address. When DECthreads receives a condition it does not handle (including SS$_UNWIND, SS$_DEBUG, or a condition code that does not have a SEVERE severity), DECthreads invokes the saved condition handler. The condition handler will be reestablished when the TRY block exits.
On OpenVMS Alpha, system calls are now cancelation points for threads created using the POSIX 1003.1c style interface. System calls are not cancelation points for threads in legacy multithreaded applications that were created using the Digital-proprietary CMA (or cma) or POSIX 1003.4a/Draft 4 (or d4) interfaces. None of the system calls should be called with asynchronous cancelation enabled. For more information, see Section 2.3.7.
On OpenVMS Alpha, DECthreads supports the use of 64-bit addressing in the pthread interface only. When compiling with the following command, the pthread_join() function returns a 64-bit void* value as the result:
$ CC/POINTER_SIZE=LONG
6493P015.HTM OSSG Documentation 22-NOV-1996 13:20:19.29
Copyright © Digital Equipment Corporation 1996. All Rights Reserved.