[Digital logo]
[HR]

Guide to DECthreads


Previous | Contents

int
tis_write_unlock (
tis_rwlock_t *lock);


ARGUMENTS

lock

Address of the readers/writer lock.

DESCRIPTION

This routine unlocks a readers/writer lock that was acquired in write access mode.

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 Values If an error condition occurs, this routine returns an integer value indicating the type error. Possible return values are as follows:
Return Description
0 Successful completion.
[EINVAL] The value specified by lock is invalid.

Associated Routines


Part 4
Appendixes

Part 4 contains appendixes that provide supporting information about DECthreads, such as operating system-specific information, debugging information, and additional reference information.


Appendix A
Considerations for Digital UNIX Systems

This appendix discusses DECthreads issues specific to Digital UNIX systems.

A.1 Overview

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.

A.2 Building with DECthreads

The following sections discuss points to consider when building using DECthreads.

A.2.1 Including DECthreads Header Files

Include one of the DECthreads header files shown in Table A-1 in your program to use the appropriate DECthreads library.

Table A-1 DECthreads Header Files
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.

A.2.2 Building Multithreaded Applications Libraries

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.

Table A-2 Digital UNIX Shared Libraries for Multithreaded Programs
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

A.2.3 Linking Multithreaded Shared Libraries

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 

A.2.4 Compiling Applications With the tis Interface

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).

A.3 Two-Level Scheduling on Digital UNIX Systems

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).

A.3.1 DECthreads Use of Kernel Threads

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.

A.3.2 Support for Real-Time Scheduling

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.

A.4 Thread Cancelability of System Services

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.

A.4.1 Current Cancelation Points

The following functions are cancelation points:
accept()
      
aio_suspend()
close()
connect()
creat()
fcntl()
fsync()
mq_receive()
q_send()
msync()
nanosleep()
open()
pause()
pthread_cond_timedwait()
pthread_cond_wait()
pthread_delay_np()
pthread_join()
pthread_testcancel()
read()
readv()
recv()
recvfrom()
      
recvmsg()
select()
sem_wait()
send()
sendmsg()
sendto()
shutdown()
sigwaitinfo()
sigsuspend()
sigtimedwait()
sigwait()
sleep()
system()
tcdrain()
wait()
waitpid()
write()
writev()

A.4.2 Future Cancelation Points

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()
      
ctermid()
fclose()
fflush()
fgetc()
fgets()
fopen()
fprintf()
fputc()
fputs()
fread()
freopen()
fscanf()
fseek()
ftell()
fwrite()
getc()
getc_unlocked()
getchar()
getcwd()
getgrgid()
getgrgid_r()
getgrnam()
getgrnam_r()
getlogin()
getlogin_r()
getpwnam()
      
getpwnam_r()
gets()
lseek()
opendir()
perror()
printf()
putc()
putc_unlocked()
putchar()
putchar_unlocked()
puts()
readdir()
remove()
rename()
rewind()
rewinddir()
scanf()
tmpfile()
tmpname()
ttyname()
ttyname_r()
ungetc()
unlink()

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.

A.5 Using Signals

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.

A.5.1 POSIX sigwait Service

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().

A.5.2 Handling Signals as Exceptions

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.

Table A-3 Signals Reported as Exceptions
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

A.6 Dynamic Activation

Dynamic activation of DECthreads, or of code that depends on DECthreads, is currently not supported.


Appendix B
Considerations for OpenVMS Systems

This appendix discusses DECthreads issues and restrictions specific to the OpenVMS operating system.

B.1 Overview

Under OpenVMS, DECthreads offers these application programming interfaces:

B.2 Including DECthreads Header Files

The DECthreads C language header files shown in Table B-1 provide interface definitions for DECthreads APIs.

Table B-1 DECthreads Header Files
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.

B.3 Compiling OpenVMS Images

Special compiler definitions are not required when compiling threaded applications that use the pthread interface or the tis interface.

B.4 Linking OpenVMS Images

When you link an image that calls DECthreads routines, you must link against the appropriate images listed in Table B-2.

Table B-2 DECthreads Images
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.

B.5 Using DECthreads with Asynchronous System Trap Routines

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:

B.6 Dynamic Activation

Dynamic activation of DECthreads (or images that depend on DECthreads) is currently not supported.

B.7 Declaring an OpenVMS Condition Handler

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.

B.8 Thread Cancelability of System Services

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.

B.9 Using OpenVMS Alpha 64-Bit Addressing

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 
 


Previous | Next | Contents | [Home] | [Comments] | [Ordering info] | [Help]

[HR]

  6493P015.HTM
  OSSG Documentation
  22-NOV-1996 13:20:19.29

Copyright © Digital Equipment Corporation 1996. All Rights Reserved.

Legal