Analyzing Program Performance With Sun WorkShop

LockLint Subcommands

Some of these are equivalent to subcommands such as assert. Source code annotations are often preferable to subcommands, because they

analyze

analyze has the following syntax:


analyze [-hv]

Analyzes the loaded files for lock inconsistencies that may lead to data races and deadlocks. This subcommand may produce a great deal of output, so you may want to redirect the output to a file. This subcommand can be run only once for each saved state. (See "save").

-h (history) produces detailed information for each phase of the analysis. No additional errors are issued.

-v (verbose) generates additional messages during analysis:

The output messages are likely to reflect situations that are not real problems; therefore, it is often helpful to first analyze the code without the -v option, to show only the messages that are likely to represent real problems.

LockLint analyze Phases

Each problem encountered during analysis is reported on one or more lines, the first of which begins with an asterisk. Where possible, LockLint provides a complete traceback of the calls taken to arrive at the point of the problem. The analysis goes through the following phases:

  1. Checking for functions with variable side effects on locks

    If a disallow sequence specifies that a function with locking side effects should not be analyzed, LockLint produces incorrect results. If such disallow sequences are found, they are reported and analysis does not proceed.

  2. Preparing locks to hold order info

    LockLint processes the asserted lock order information available to it. If LockLint detects a cycle in the asserted lock order, the cycle is reported as an error.

  3. Checking for function pointers with no targets

    LockLint cannot always deduce assignments to function pointers. During this phase, LockLint reports any function pointer for which it does not think there is at least one target, whether deduced from the source or declared a func.ptr target.

  4. Removing accesses to ignored variables

    To improve performance, LockLint removes references to ignored variables at this point. (This affects the output of the vars subcommands.)

  5. Preparing functions for analysis

    During this phase, LockLint determines what side effects each function has on locks. (A side effect is a change in a lock's state that is not reversed before returning.) An error results if

    • The side effects do not match what LockLint expects

    • The side effects are different depending upon the path taken through the function

    • A function with such side effects is recursive

    LockLint expects that a function will have no side effects on locks, except where side effects have been added using the assert side effect subcommand.

  6. Preparing to recognize calling sequences to allow/disallow

    Here LockLint is processing the various allow/disallow subcommands that were issued, if any. No errors or warnings are reported.

  7. Checking locking side effects in function pointer targets

    Calls through function pointers may target several functions. All functions that are targets of a particular function pointer must have the same side effects on locks (if any). If a function pointer has targets that differ in their side effects, analysis does not proceed.

  8. Checking for consistent use of locks with condition variables

    Here LockLint checks that all waits on a particular condition variable use the same mutex. Also, if you assert that particular lock to protect that condition variable, LockLint makes sure you use that lock when waiting on the condition variable.

  9. Determining locks consistently held when each function is entered

    During this phase, LockLint reports violations of assertions that locks should be held upon entry to a function (see assert subcommand). Errors such as locking a mutex lock that is already held, or releasing a lock that is not held, are also reported. Locking an anonymous lock, such as foo::lock, more than once is not considered an error, unless the declare one command has been used to indicate otherwise. (See "Lock Inversions" for details on anonymous data.)

  10. Determining locks consistently held when each variable is accessed

    During this phase, LockLint reports violations of assertions that a lock should be held when a variable is accessed (see the assert subcommand). Also, any writes to read-only variables are reported.

    Occasionally you may get messages that certain functions were never called. This can occur if a set of functions (none of which are root functions) call each other. If none of the functions is called from outside the set, LockLint reports that the functions were never called at all. The declare root subcommand can be used to fix this situation for a subsequent analysis.

    Using the disallow subcommand to disallow all sequences that reach a function will also cause a message that the function is never called.

Once the analysis is done, you can find still more potential problems in the output of the vars and order subcommands.

assert

assert has the following syntax:

assert side effect

mutex

acquired in 

func ...

assert side effect

rwlock [read]

acquired in 

func ...

assert side effect

lock

released in 

func ...

assert side effect

rwlock

upgraded in 

func ...

assert side effect

rwlock

downgraded in 

func ...

assert mutex|rwlock

protects 

 

var ...

assert mutex

protects 

 

func ...

assert rwlock

protects 

[reads in] 

func ...

assert order

 

 

lock lock ...

assert read only

 

 

var ...

assert rwlock

covers 

 

lock ...

These subcommands tell LockLint how the programmer expects locks and variables to be accessed and modified in the application being checked. During analysis any violations of such assertions are reported.


Note -

If a variable is asserted more than once, only the last assert takes effect.


assert side effect

A side effect is a change made by a function in the state of a lock, a change that is not reversed before the function returns. If a function contains locking side effects and no assertion is made about the side effects, or the side effects differ from those that are asserted, a warning is issued during the analysis. The analysis then continues as if the unexpected side effect never occurred.


Note -

There is another kind of side effect called an inversion. See "Lock Inversions", and the locks or funcs subcommands, for more details.


Warnings are also issued if the side effects produced by a function could differ from call to call (for example, conditional side effects). The keywords acquired in, released in, upgraded in, and downgraded in describe the type of locking side effect being asserted about the function. The keywords correspond to the side effects available via the threads library interfaces and the DDI and DKI Kernel Functions (see mutex(3T), rwlock(3T), mutex(9F) and rwlock(9F)).

The side effect assertion for rwlocks takes an optional argument read; if read is present, the side effect is that the function acquires read-level access for that lock. If read is not present, the side effect specifies that the function acquires write-level access for that lock.

assert mutex|rwlock protects

Asserting that a mutex lock protects a variable causes an error whenever the variable is accessed without holding the mutex lock. Asserting that a readers-writer lock protects a variable causes an error whenever the variable is read without holding the lock for read access or written without holding the lock for write access. Subsequent assertions as to which lock protects a variable override any previous assertions; that is, only the last lock asserted to protect a variable is used during analysis.

assert mutex protects

Asserting that a mutex lock protects a function causes an error whenever the function is called without holding the lock. For root functions, the analysis is performed as if the root function were called with this assertion being true.

assert rwlock protects

Asserting that a readers-writer lock protects a function causes an error whenever the function is called without holding the lock for write access. Asserting that a readers-writer lock protects reads in a function causes an error whenever the function is called without holding the lock for read access. For root functions, the analysis is performed as if the root function were called with this assertion being true.


Note -

To avoid flooding the output with too many violations of a single assert... protects subcommand, a maximum of 20 violations of any given assertion is shown. This limit does not apply to the assert order subcommand.


assert order

Informs LockLint of the order in which locks should be acquired. That is, LockLint assumes that the program avoids deadlocks by adhering to a well-known lock order. Using this subcommand, you can make LockLint aware of the intended order so that violations of the order can be printed during analysis.

assert read only

States that the given set of variables should never be written by the application; LockLint reports any writes to the variables. Unless a variable is read-only, reading the variable while no locks are held will elicit an error since LockLint assumes that the variable could be written by another thread at the same time.

assert rwlock covers

Informs LockLint of the existence of a hierarchical locking relationship. A readers-writer lock may be used in conjunction with other locks (mutex or readers-writer) in the following way to increase performance in certain situations:

declare

declare has the following syntax:

declare

mutex

mutex . . .

 

declare

rwlocks

rwlock ...

 

declare

func_ptr

targets

func ...

declare

nonreturning

func ...

 

declare

one

tag ...

 

declare

readable

var ...

 

declare

root

func ...

 

These subcommands tell LockLint things that it cannot deduce from the source presented to it.

declare mutex mutexdeclare rwlocks rwlock

These subcommands (along with declare root, below) are typically used when analyzing libraries without a supporting harness. The subcommands declare mutex and declare rwlocks create mutex and reader-writer locks of the given names. These symbols can be used in subsequent assert subcommands.

declare func_ptr targets func

Adds the specified functions to the list of functions that could be called through the specified function pointer.

LockLint manages to gather a good deal of information about function pointer targets on its own by watching initialization and assignments. For example, for the code


struct foo { int (*fp)(); } foo1 = { bar };

LockLint does the equivalent of the command


% lock_lint declare foo::fp targets bar


Caution - Caution -

LockLint does not yet do the following (for the above example):


% lock_lint declare foo1.fp targets bar

However, it does manage to do both for assignments to function pointers. See "Lock Inversions".


declare nonreturning func

Tells LockLint that the specified functions do not return. LockLint will not give errors about lock state after calls to such functions.

declare one tag

Tells LockLint that only one unnamed instance exists of each structure whose tag is specified. This knowledge makes it possible for LockLint to give an error if a lock in that structure is acquired multiple times without being released. Without this knowledge, LockLint does not complain about multiple acquisitions of anonymous locks (for example, foo::lock), since two different instances of the structure could be involved. (See "Lock Inversions".)

declare readable var

Tells LockLint that the specified variables may be safely read without holding any lock, thus suppressing the errors that would ordinarily occur for such unprotected reads.

declare root func

Tells LockLint to analyze the given functions as a root function; by default, if a function is called from any other function, LockLint does not attempt to analyze that function as the root of a calling sequence.

A root function is a starting point for the analysis; functions that are not called from within the loaded files are naturally roots. This includes, for example, functions that are never called directly but are the initial starting point of a thread (for example, the target function of a thread_create call). However, a function that is called from within the loaded files might also be called from outside the loaded files, in which case you should use this subcommand to tell LockLint to use the function as a starting point in the analysis.

disallow

disallow has the following syntax:


disallow func ...

Tells LockLint that the specified calling sequence should not be analyzed. For example, to prevent LockLint from analyzing any calling sequence in which f() calls g() calls h(), use the subcommand


% lock_lint disallow f g h

Function pointers can make a program appear to follow many calling sequences that do not in practice occur. Bogus locking problems, particularly deadlocks, can appear in such sequences. (See also the description of the subcommand "reallow".) disallow prevents LockLint from following such sequences.

disallows

disallows has the following syntax:


disallows

Lists the calling sequences that are disallowed by the disallow subcommand.

exit

There is no exit subcommand for LockLint. To exit LockLint, use the exit command for the shell you are using.

files

files has the following syntax:


files

Lists the .ll versions of the source code files loaded with the load subcommand.

funcptrs

funcptrs has the following syntax:


funcptrs [-botu] func_ptr ...  
funcptrs [-blotuz]

Lists information about the function pointers used in the loaded files. One line is produced for each function pointer.

Table A-6 funcptrs Options
 Option Definition 

-b

(bound) This option lists only function pointers to which function targets have been bound, that is it suppresses the display of function pointers for which there are no bound targets.

-l

(long) Equivalent to -ot.

-o

(other) This presents the following information about each function pointer:

Calls=#

Indicates the number of places in the loaded files this function pointer is used to call a function. 

=nonreturning

Indicates that a call through this function pointer never returns (none of the functions targeted ever return). 

-t

(targets) This option lists the functions currently bound as targets to each function pointer listed, as follows:targets={ func ... }

-u

(unbound) This lists only those function pointers to which no function targets are bound. That is, suppresses the display of function pointers for which there are bound targets.

-z 

(zero) This lists function pointers for which there are no calls. Without this option information is given only on function pointers through which calls are made.

You can combine various options to funcptrs:

funcs

funcs has the following syntax:

funcs [-adehou]

 

 

func ...

funcs [-adehilou]

[directly] 

 

 

funcs [-adehlou]

[directly] 

called by 

func ...

funcs [-adehlou]

[directly] 

calling 

func ...

funcs [-adehlou]

[directly] 

reading 

var ....

funcs [-adehlou]

[directly] 

writing 

var ...

funcs [-adehlou]

[directly] 

accessing 

var ...

funcs [-adehlou]

[directly] 

affecting 

lock ...

funcs [-adehlou]

[directly] 

inverting 

lock ...

funcs lists information about the functions defined and called in the loaded files. Exactly one line is printed for each function.

Table A-7 funcs Options

Option 

Definition 

 

-a 

(asserts) This option shows information about which locks are supposed to be held on entry to each function, as set by the assert subcommand. When such assertions have been made, they show as:

asserts={ lock ... }

read_asserts={ lock ... }

An asterisk appears before the name of any lock that was not consistently held upon entry (after analysis). 

-e

(effects) This option shows information about the side effects each function has on locks (for example, "acquires mutex lock foo"). If a function has such side effects, they are shown as:

side_effects={ effect [, effect] ... }

Using this option prior to analysis shows side effects asserted by an assert side effect subcommand. After analysis, information on side effects discovered during the analysis is also shown.

-d

(defined) This option shows only those functions that are defined in the loaded files. That is, that it suppresses the display of undefined functions.

-h

(held) This option shows information about which locks were consistently held when the function was called (after analysis). Locks consistently held for read (or write) on entry show as:

held={ lock ... }+{ lock ... }

read_held={ lock ... }+{ lock ... }

The first list in each set is the list of locks consistently held when the function was called; the second is a list of inconsistently held locks--locks that were sometimes held when the function was called, but not every time.

-i

(ignored) This option lists ignored functions.

-l

(long) Equivalent to -aeoh.

-o

(other) This option causes LockLint to present, where applicable, the following information about each function

=ignored

Indicates that LockLint has been told to ignore the function using the ignore subcommand.

=nonreturning

Indicates that a call through this function never returns (none of the functions targeted ever return). 

=rooted

Indicates that the function was made a root using the declare root subcommand.

=root

Indicates that the function is naturally a root (is not called by any function). 

=recursive

Indicates that the function makes a call to itself. 

=unanalyzed

Indicates that the function was never called during analysis (and is therefore unanalyzed). This differs from =root in that this can happen when foo calls bar and bar calls foo, and no other function calls either foo or bar, and neither have been rooted (see =rooted). So, because foo and bar are not roots, and they can never be reached from any root function, they have not been analyzed.

calls=#

Indicates the number of places in the source code, as represented by the loaded files, where this function is called. These calls may not actually be analyzed; for example, a disallow subcommand may prevent a call from ever really taking place.

-u

(undefined) This option shows only those functions that are undefined in the loaded files.

funcs [-adehou] func ...

Lists information about individual functions. By default, this variant of the subcommand gives all the details about the functions, as if -aeho had been specified.

funcs [-adehilou]

Lists information about all functions that are not ignored. If -i is used, even ignored functions are listed.

funcs [-adehlou] [directly] called by func ...

Lists only those functions that may be called as a result of calling the specified functions. If directly is used, only those functions called by the specified functions are listed. If directly is not used, any functions those functions called are also listed, and so on.

funcs [-adehlou] [directly] calling func ...

Lists only those functions that, when called, may result in one or more of the specified functions being called. See notes below on directly.

funcs [-adehlou] [directly] reading var ...

Lists only those functions that, when called, may result in one or more of the specified variables being read. See notes below on directly.

funcs [-adehlou] [directly] writing var ...

Lists only those functions that, when called, may result in one or more of the specified variables being written. See notes below on directly.

funcs [-adehlou] [directly] accessing var ...

Lists only those functions that, when called, may result in one or more of the specified variables being accessed (read or written). See notes below on directly.

funcs [-adehlou] [directly] affecting lock ...

Lists only those functions that, when called, may result in one or more of the specified locks being affected (acquired, released, upgraded, or downgraded). See notes below on directly.

funcs [-adehlou] [directly] inverting lock ...

Lists only those functions that invert one or more of the specified locks. (See "Lock Inversions".) If directly is used, only those functions that themselves invert one or more of the locks (actually release them) are listed. If directly is not used, any function that is called with a lock already held, and then calls another function that inverts the lock, is also listed, and so on.

For example, in the following code, f3() directly inverts lock m, and f2() indirectly inverts it:


f1() { pthread_mutex_unlock(&m); f2(); pthread_mutex_lock(&m); }
f2() { f3(); }
f3() { pthread_mutex_unlock(&m); pthread_mutex_lock(&m); } 

About directly

Except where stated otherwise, variants that allow the keyword directly only list the functions that themselves fit the description. If directly is not used, all the functions that call those functions are listed, and any functions that call those functions, and so on.

help

help has the following syntax:


help [keyword]

Without a keyword, help displays the subcommand set.

With a keyword, help gives helpful information relating to the specified keyword. The keyword may be the first word of any LockLint subcommand. There are also a few other keywords for which help is available:


condvars
locking
example
makefile
ifdef
names
inversions
overview
limitations
shell

If environment variable PAGER is set, that program is used as the pager for help. If PAGER is not set, more is used.

ignore

ignore has the following syntax:


ignore
 func|var ...  [ in func ...  ]

Tells LockLint to exclude certain functions and variables from the analysis. This exclusion may be limited to specific functions using the in func ... clause; otherwise the exclusion applies to all functions.

The commands


% lock_lint funcs -io | grep =ignored
% lock_lint vars -io | grep =ignored

show which functions and variables are ignored.

load

load has the following syntax:


load file ...

Loads the specified .ll files. The extension may be omitted, but if an extension is specified, it must be .ll. Absolute and relative paths are allowed. You are talking to a shell, so the following are perfectly legal (depending upon your shell's capabilities):


% lock_lint load *.ll
% lock_lint load ../foo/abcdef{1,2}
% lock_lint load `find .  -name \*.ll -print`

The text for load is changed extensively. To set the new text, type:


% lock_lint help load

locks

locks has the following syntax:


locks [-co] lock ...
locks [-col]
locks [-col] [directly] affected by func ...
locks [-col] [directly] inverted by func ...

Lists information about the locks of the loaded files. Only those variables that are actually used in lock manipulation routines are shown; locks that are simply declared but never manipulated are not shown.

Table A-8 locks Options

Option 

Definition 

-c

(cover) This option shows information about lock hierarchies. Such relationships are described using the assert rwlock covers subcommand. (When locks are arranged in such a hierarchy, the covering lock must be held, at least for read access, whenever any of the covered locks is held. While holding the covering lock for write access, it is unnecessary to acquire any of the covered locks.) If a lock covers other locks, those locks show as

covered={ lock ... }

If a lock is covered by another lock, the covering lock shows as 

cover=lock 

-l

(long) Equivalent to -co.

-o

(other) Causes the type of the lock to be shown as (type) where type is mutex, rwlock, or ambiguous type [used as a mutex in some places and as a rwlock (readers-writer) in other places].

locks [-co] lock ...

Lists information about individual locks. By default, this variant of the subcommand gives all the details about the locks, as if -co had been specified.

locks [-col]

Lists information about all locks.

locks [-col] [directly] affected by func ...

Lists only those locks that may be affected (acquired, released, upgraded, or downgraded) as a result of calling the specified functions. If the keyword directly is used, only functions that use the threads library routines directly to affect a lock (acquire, release, upgrade, or downgrade) are listed. If the keyword directly is not used, any function that calls a function that affects a lock will be listed, and any function calling that function are listed, and so on.

locks [-col] [directly] inverted by func ...

Lists only those locks that may be inverted by calling one of the specified functions. (See "Lock Inversions".)

If the keyword directly is used, only those locks that are directly inverted by the specified functions (that is, the functions that actually release and reacquire locks using a threads library routine) are listed. If the keyword directly is not used, a lock that is held by one of the specified functions and inverted by some function called from it (and so on) is also listed. For example, in the following code f1 directly inverts m1, and indirectly inverts m2.


f1() { pthread_mutex_unlock(&m1); f2(); pthread_mutex_lock(&m1); }
f2() { f3(); }
f3() { pthread_mutex_unlock(&m2); pthread_mutex_lock(&m2); } 

members

members has the following syntax:


members struct_tag

Lists the members of the struct with the specified tag, one per line. For structures that were not assigned a tag, the notation file@line is used (for example, x.c@29), where the file and line number are the source location of the struct declaration.

members is particularly useful to use as input to other LockLint subcommands. For example, when trying to assert that a lock protects all the members of a struct, the following command suffices:


% lock_lint assert foo::lock protects `lock_lint members foo`


Note -

The members subcommand does not list any fields of the struct that are defined to be of type mutex_t, rwlock_t, krwlock_t, or kmutex_t.


order

order has the following syntax:


order [lock [lock]]
order summary

The order subcommand lists information about the order in which locks are acquired by the code being analyzed. It may be run only after the analyze subcommand.

order [lock [lock]]

Shows the details about lock pairs. For example, the command


% lock_lint order foo bar

shows whether an attempt was made to acquire lock bar while holding lock foo. The output looks something like the following:


:foo :bar seen (first never write-held), valid

First the output tells whether such an attempt actually occurred (seen or unseen). If the attempt occurred, but never with one or both of the locks write-held, a parenthetical message to that effect appears, as shown. In this case, foo was never write-held while acquiring bar.

If an assertion was made about the lock order, the output shows whether the specified order is valid or invalid according to the assertion. If there was no assertion about the order of foo and bar, or if both orders were asserted (presumably because the user wanted to see all places where one of the locks was held while acquiring the other), the output indicates neither valid nor invalid.

order summary

Shows in a concise format the order in which locks are acquired. For example, the subcommand might show


:f :e :d :g :a
:f :c :g :a

In this example, there are two orders because there is not enough information to allow locks e and d to be ordered with respect to lock c.

Some cycles are shown, while others are not. For example,

:a :b :c :b

is shown, but

:a :b :c :a

(where no other lock is ever held while trying to acquire one of these) is not. Deadlock information from the analysis is still reported.

pointer calls

pointer calls has the following syntax:


pointer calls

Lists calls made through function pointers in the loaded files. Each call is shown as:


function [location of call] calls through funcptr func_ptr

For example,


foo.c:func1 [foo.c,84] calls through funcptr bar::read

means that at line 84 of foo.c, in func1 of foo.c, the function pointer bar::read (member read of a pointer to struct of type bar) is used to call a function.

reallow

reallow has the following syntax:


reallow func ...

Allows you to make exceptions to disallow subcommands. For example, to prevent LockLint from analyzing any calling sequence in which f() calls g() calls h(), except when f() is called by e() which was called by d(), use the commands


% lock_lint disallow f g h
% lock_lint reallow d e f g h

In some cases you may want to state that a function should only be called from a particular function, as in this example:


% lock_lint disallow f
% lock_lint reallow e f


Note -

A reallow subcommand only suppresses the effect of a disallow subcommand if the sequences end the same. For example, after the following commands, the sequence d e f g h would still be disallowed:


% lock_lint disallow e f g h
% lock_lint reallow d e f g


reallows

reallows has the following syntax:


reallows

Lists the calling sequences that are reallowed, as specified using the reallow subcommand.

refresh

refresh has the following syntax:


refresh

Pops the saved state stack, restoring LockLint to the state of the top of the saved-state stack, prints the description, if any, associated with that state, and saves the state again. Equivalent to restore followed by save.

restore

restore has the following syntax:


restore

Pops the saved state stack, restoring LockLint to the state of the top of the saved-state stack, and prints the description, if any, associated with that state.

The saved state stack is a LIFO (Last-In-First-Out) stack. Once a saved state is restored (popped) from the stack, that state is no longer on the saved-state stack. If the state needs to be saved and restored repeatedly, simply save the state again immediately after restoring it, or use the refresh subcommand.

save

save has the following syntax:


save description

Saves the current state of the tool on a stack. The user-specified description is attached to the state. Saved states form a LIFO (Last-In-First-Out) stack, so that the last state saved is the first one restored.

This subcommand is commonly used to save the state of the tool before running the analyze subcommand, which can be run only once on a given state. For example, you can do the following:


%: lock_lint load *.ll
%: lock_lint save Before Analysis
%: lock_lint analyze
	<output from analyze>
%: lock_lint vars -h | grep \*
	<apparent members of struct foo are not consistently protected>
%: lock_lint refresh Before Analysis
%: lock_lint assert lock1 protects `lock_lint members foo`
%: lock_lint analyze
	<output now contains info about where the assertion is violated>

saves

saves has the following syntax:


saves

Lists the descriptions of the states saved on the saved stack via the save subcommand. The descriptions are shown from top to bottom, with the first description being the most recently saved state that has not been restored, and the last description being the oldest state saved that has not been restored.

start

start has the following syntax:


start [cmd]

Starts a LockLint session. A LockLint session must be started prior to using any other LockLint subcommand. By default, start establishes LockLint's context and starts a subshell for the user, as specified via $SHELL, within that context. The only piece of the LockLint context exported to the shell is the environment variable LL_CONTEXT, which contains the path to the temporary directory of files used to maintain a LockLint session.

cmd specifies a command and its path and options. By default, if cmd is not specified, the value of $SHELL is used.


Note -

To exit a LockLint session use the exit command of the shell you are using.


See "Limitations of LockLint", for more on setting up the LockLint environment for a start subcommand.

Start Examples

The following examples show variations of the start subcommand.

Using the default


% lock_lint start

LockLint's context is established and LL_CONTEXT is set. Then the program identified by $SHELL is executed. Normally, this is your default shell. LockLint subcommands can now be entered. Upon exiting the shell, the LockLint context is removed.

Using a pre-written script


% lock_lint start foo

The LockLint context is established and LL_CONTEXT is set. Then, the command /bin/csh -c foo is executed. This results in executing the C shell command file foo, which contains LockLint commands. Upon completing the execution of the commands in foo by /bin/csh, the LockLint context is removed.

If you use a shell script to start LockLint, insert #! in the first line of the script to define the name of the interpreter that processes that script. For example, to specify the C-shell the first line of the script is:

#! /bin/csh

Starting up with a specific shell

In this case, the user starts LockLint with the Korn shell:


% lock_lint start /bin/ksh

After establishing the LockLint context and setting LL_CONTEXT, the command /bin/ksh is executed. This results in the user interacting with an interactive Korn shell. Upon exiting the Korn shell, the LockLint context is removed.

sym

sym has the following syntax:


sym name ...

Lists the fully qualified names of various things the specified names could refer to within the loaded files. For example, foo might refer both to variable x.c:func1/foo and to function y.c:foo, depending on context.

unassert

unassert has the following syntax:


unassert vars var ...

Undoes any assertion about locks protecting the specified variables. There is no way to remove an assertion about a lock protecting a function.

vars

vars has the following syntax:


vars [-aho] var ...
vars [-ahilo]
vars [-ahlo] protected by lock
vars [-ahlo] [directly] read by func ...
vars [-ahlo] [directly] written by func ...
vars [-ahlo] [directly] accessed by func ...

Lists information about the variables of the loaded files. Only those variables that are actually used are shown; variables that are simply declared in the program but never accessed are not shown.

Table A-9 vars Options

Option

Definition 

 

-a

(assert) Shows information about which lock is supposed to protect each variable, as specified by the assert mutex|rwlock protects subcommand. The information is shown as follows assert=lock

If the assertion is violated, then after analysis this will be preceded by an asterisk, such as *assert=<lock>.

-h

(held) Shows information about which locks were consistently held when the variable was accessed. This information is shown after the analyze subcommand has been run. If the variable was never accessed, this information is not shown. When it is shown, it looks like this:

held={ <lock> ... }

If no locks were consistently held and the variable was written, this is preceded by an asterisk, such as *held={ }. Unlike funcs, the vars subcommand lists a lock as protecting a variable even if the lock was not actually held, but was simply covered by another lock. (See assert rwlock covers in the description of "assert".)

-i

(ignored) causes even ignored variables to be listed.

-l

(long) Equivalent to -aho.

-o

(other) Where applicable, shows information about each variable

=cond_var

Indicates that this variable is used as a condition variable. 

=ignored

Indicates that LockLint has been told to ignore the variable explicitly via an ignore subcommand.

=read-only

Means that LockLint has been told (by assert read only) that the variable is read-only, and will complain if it is written. If it is written, then after analysis this will be followed by an asterisk, such as =read-only* for example.

=readable

Indicates that LockLint has been told by a declare readable subcommand that the variable may be safely read without holding a lock.

=unwritten

May appear after analysis, meaning that while the variable was not declared read-only, it was never written. 

vars [-aho] var ...

Lists information about individual variables. By default, this variant of the subcommand gives all the details about the variables, as if -aho had been specified.

vars [-ahilo]

Lists information about all variables that are not ignored. If -i is used, even ignored variables are listed.

vars [-ahlo] protected by lock

Lists only those variables that are protected by the specified lock. This subcommand may be run only after the analyze subcommand has been run.

vars [-ahlo] [directly] read by func ...

Lists only those variables that may be read as a result of calling the specified functions. See notes below on directly.

vars [-ahlo] [directly] written by func ...

Lists only those variables that may be written as a result of calling the specified functions. See notes below on directly.

vars [-ahlo] [directly] accessed by func ...

Lists only those variables that may be accessed (read or written) as a result of calling the specified functions.

About directly

Those variants that list the variables accessed by a list of functions can be told to list only those variables that are directly accessed by the specified functions. Otherwise the variables accessed by those functions, the functions they call, the functions those functions call, and so on, are listed.