Although the result is not reliable, you can use explicit locks either instead of perimeters or to augment the concurrency restrictions provided by the perimeters.
Explicit locks cannot be used to preserve message ordering in a module because of the risk of reentering the module. Use MT STREAMS perimeters to preserve message ordering.
All four types of kernel synchronization primitives are available to the module writer: mutexes, readers/writer locks, semaphores, and condition variables. Since cv_wait implies a context switch, it can only be called from the module's open and close procedures, which are executed with valid process context. You must use the synchronization primitives to protect accesses and ensure the integrity of private module data structures.
When adding locks in a module, it is important to observe these constraints:
Avoid holding module private locks across calls to putnext(9F). The module might be reentered by the same thread that called putnext(9F), causing the module to try to acquire a lock that it already holds. This can cause kernel panic.
Do not hold module private locks, acquired in put or service procedures, across the calls to qprocson(9F) or qprocsoff(9F). Doing this causes deadlock, since qprocson(9F) and qprocsoff) wait until all threads leave the inner perimeter.
Similarly, do not hold locks, acquired in the timeout(9F) and bufcall(9F) callback procedures, across the calls to untimeout(9F) or unbufcall(9F). Doing this causes deadlock, since untimeout(9F)and unbufcall(9F) wait until an already executing callback has completed.
The first restriction makes it hard to use module private locks to preserve message ordering. MT STREAMS perimeters is the preferred mechanism to preserve message ordering.
Module private locks cannot be used to preserve message ordering, since they cannot be held across calls to putnext(9F) and the other messages that pass routines to other modules. The alternatives for preserving message ordering are:
Use MT STREAMS perimeters.
Pass all messages through the service procedures. The service procedure can drop the locks before calling putnext(9F) or qreply(9F), without reordering messages, since the framework guarantees tha,t at most, one thread will execute in the service procedure for a given queue.
Use perimeters since there is a performance penalty for using service procedures.