This chapter contains notes about issues and known problems with the development environment software and, whenever possible, provides solutions or ways to avoid the problems. The following topics are discussed:
General programming (Section 6.1)
POSIX Threads Library (Section 6.2)
Kernel programming (Section 6.3)
The following notes apply to general programming.
6.1.1 Change to bcopy, bcmp, and bzero
The argument types for the
bcopy
,
bcmp
, and
bzero
system functions have been changed
to conform to the ANSI specification.
The new interface prototypes are as
follows:
int bcmp __((const void *, const void *, size_t); int bcopy __((const void *, void *, size_t); int bzero __((void *, size_t);
You can access the old prototype
definitions by compiling applications using the
-D__V40_OBJ_COMPAT
compile flag.
For example:
> cc -D__V40_OBJ_COMPAT test.c
6.1.2 Change to struct utmp, struct utmpx, and struct lastlog
To bring them
into compliance with several UNIX and Internet standards, the
struct
utmp
,
struct utmpx
, and
struct lastlog
structures were updated in Version 5.0.
These changes affect the
/usr/include/utmp.h
,
/usr/include/utmpx.h
, and
/usr/include/lastlog.h
file.
6.1.3 The getaddrinfo() Routine Might Return the Incorrect Return Status
Under the following circumstances, the
getaddrinfo()
routine returns an incorrect status to the application:
If the address family in the hints is not specified (PF_UNSPEC
) or the parameter is NULL, the
getaddrinfo()
routine incorrectly returns the status as
EAI_FAMILY
.
The
getaddrinfo()
routine incorrectly returns
the status as
EAI_SERVICE
under the following circumstances:
The
servname
parameter is specified as
the name of the service that exists in the
/etc/services
file.
The
ai_socktype
and
ai_protocol
addrinfo
structure members are not specified.
The service, specified in the
servname
parameter, only has TCP protocol listed in the
/etc/services
file.
To avoid these problems, check the
res
pointer to
make sure that it is valid.
6.1.4 Time Zone Environment Variable Setting
If the
TZ
environment variable is set to
:
(colon), as in
TZ=:
, either on the command line or via a
putenv()
call, the data for the default time zone (GMT), used by time-related
libc
functions (such as
tzset()
,
mktime()
, and
localtime()
), is not loaded as it should
be.
A setting of
TZ=:
might result in programs producing
empty time zone abbreviations or using time zone data that is erroneously
consistent with a previous time zone used by the same program.
It might also
lead to errors from the
mktime()
function when valid input
is supplied.
The
TZ=:pathname
syntax and other
TZ
formats continue to work correctly.
Only the
TZ=:
syntax
is affected.
In this release, setting the
TZ
environment variable
to either
TZ=:Etc/GMT
or
TZ=GMT0
produces
the same behavior as the
TZ=:
setting.
6.2 POSIX Threads Library (pthreads)
DECthreads has been renamed the POSIX Threads Library. Compaq has made enhancements to the library to improve the performance of some classes of threaded applications.
The following notes apply to the POSIX Threads Library.
6.2.1 pthread_mutex_destroy() Can Return EBUSY for Unlocked Mutex
One of the possible return status values of the POSIX Threads Library
routine
pthread_mutex_destroy()
is EBUSY.
Normally, this
indicates that the mutex to be destroyed is currently locked or in use.
Attempting
to destroy a locked or in-use mutex is an application error.
Under certain timing conditions,
pthread_mutex_destroy()
can erroneously return EBUSY when the mutex is unlocked or unused.
In such
cases, the mutex is not destroyed.
If the application detects the EBUSY return
status, the call can be repeated.
Subsequent call may succeed, or may fail
with EBUSY again.
Eventually the call should succeed.
If the call is not successfully
repeated, a small amount of memory will be leaked.
6.2.2 Problems with Use of the stackaddr Thread Creation Attribute
Using the
stackaddr
thread
creation attribute, which allows you to allocate your own stack for a thread,
is not recommended.
The semantics of this attribute are poorly
defined by POSIX and the Single UNIX Specification, Version 2.
As a result,
code using the attribute is unlikely to be portable between implementations.
The attribute is difficult to use reliably, because you must, by intimate
knowledge of the machine architecture and implementation, know the correct
address to specify relative to the allocated stack.
The implementation cannot
diagnose an incorrect value because the interface does not provide sufficient
information.
Using an incorrect value might result in program failure, possibly
in obscure ways.
Alternatively, if you want to supply your own thread stacks, consider
using the
pthread_attr_setstackaddr_np()
routine.
Callers
specify the thread stack using a base address and size, which avoids the worst
problems with the standard interface.
6.2.3 Memory Alignment Issue
Although older Alpha processors (prior to the 21264 chip) can only access memory in units of at least a quadword (8 bytes), multiple variables, each of which is less than 8 bytes, can occupy the same quadword in memory. In such cases, multithreaded programs might experience a problem if two or more threads read the same quadword, update different parts of it, then independently write their respective copies back to memory. The last thread to write the quadword overwrites any data previously written to other parts of the quadword. This can happen even though each thread protects its part of the quadword with its own mutex.
The Tru64 UNIX C compiler protects scalar variables against this problem by aligning them in memory on quadword (8-byte) boundaries. However, in composite data objects such as structures or arrays, the compiler aligns members on their natural boundaries. For example, a 2-byte member is aligned on a 2-byte boundary. Because of this, any adjacent members of the composite object that total 8 bytes or less could occupy the same quadword in memory.
Inspect your multithreaded application code to determine if you have a composite data object, in which adjacent members could share the same quadword in memory. If you do and if your project allows, it is recommended that you force alignment of each such member variable to a quadword boundary by redefining the variable to be at least 8 bytes, or by defining sufficient padding storage after the variable to total 8 bytes.
Alternatively, you can create one mutex for each composite data object in which adjacent members can share the same quadword in memory. Then use this single mutex to protect all write accesses by all threads to the composite data object. This technique might be less desirable because of performance considerations.
For more information, see the Granularity Considerations section in
the
Guide to the POSIX Threads Library.
6.2.4 POSIX Threads Library pthread_debug() and pthread_debug_cmd() Routines
In order to allow for the possibility of
a more comprehensive and robust threads debugging environment, it has become
necessary to remove the
pthread_debug()
and
pthread_debug_cmd()
routines.
To prevent existing binaries from failing, the routines
will continue to be recognized.
However, a call to either routine now results
in an immediate return to the calling program.
The
pthread_debug_cmd()
routine returns a 0 (zero) indicating success.
Debuggers such
as Ladebug and TotalView provide functionality formerly provided by these
routines.
6.2.5 Process-Shared Synchronization Objects and Debugging
The POSIX Threads Library (pthread) interface now supports the sharing of certain synchronization objects (mutexes, condition variables, and read-write locks) among threads running in multiple cooperating processes. Such objects are termed process-shared objects.
For this release, process-shared objects are not visible to the Ladebug
debugger.
For example, the
show mutex
Ladebug command lists
process-private mutexes but not process-shared mutexes.
6.2.6 Use of errno
The initial or default thread in a
multithreaded application uses the global
errno
cell instead
of a perthread
errno
.
Starting in Version 5.1, use of the global
errno
cell by threads other than the initial thread (for example, by
calling nonthreadsafe or incorrectly compiled code that uses an
errno
symbol) will corrupt the initial thread's value.
Properly compiled or existing binaries using the POSIX Threads Library
will not be affected by this change.
6.3 Kernel Programming
The following notes apply to kernel programming.
6.3.1 System Call Funneling
If you are a kernel developer who implements or maintains a third-party
kernel module that "patches in" its own system call handler, and if that handler
needs to be funneled (have its execution restricted to the primary CPU), then
you will need to add the funneling hooks into the handler function.
Add a
call to
unix_master
() at the start of the handler and a
call to
unix_release
() at the end of the handler.
6.3.2 Changes to the ATM Kernel Programming Interface
To support features needed for point-to-multipoint
virtual circuits (VCs) and to provide for future enhancements, the parameters
to the
atm_cmm_register_cvg()
and
atm_cmm_register_sig()
routines have been changed.
Binary compatibility with previously compiled modules has been maintained. Convergence and signaling modules require minor source code changes when recompiled under Tru64 UNIX Version 5.1A.
See the
Asynchronous Transfer Mode
manual for more information.
6.3.3 Changes to the Internal Kernel Exception Frame
The kernel's exception frame
format has been reduced in size from 264 to 256 bytes by eliminating an unused
8-byte quadword that had been used to save the stack pointer register value.
Because this register layout is used solely for exceptions taken on a kernel
stack, this change causes no impact to applications.
However,
if you need to display the contents of an exception frame when debugging a
kernel crash dump, you now will need to interpret the data in its new 32-register
format.
6.3.4 Changes to the VFS Programming Interface
The
VFS namecache is now replicated across processors to provide lower overhead
and better scalability.
If you are developing third-party file systems,
you must be aware of the synchronization requirements with the VFS namecache.
Specifically, if you are going to delete or rename files, use the
cache_purge()
kernel call on the file.
The
namei()
kernel call removes the entry from its own namecache only (when called with
the
DELETE
or
RENAME
flag).
The
cache_purge()
kernel call invalidates the entry in all namecaches.
Additionally, when renaming files, use the
cache_purge()
kernel call on the existing target entry before you add the new name entry
to the directory.