xref: /illumos-gate/usr/src/man/man3c/mutex_init.3c (revision e8d3efa1c56e5f2b5368600a2baeb7b1d54a07f8)
1.\"
2.\" Sun Microsystems, Inc. gratefully acknowledges The Open Group for
3.\" permission to reproduce portions of its copyrighted documentation.
4.\" Original documentation from The Open Group can be obtained online at
5.\" http://www.opengroup.org/bookstore/.
6.\"
7.\" The Institute of Electrical and Electronics Engineers and The Open
8.\" Group, have given us permission to reprint portions of their
9.\" documentation.
10.\"
11.\" In the following statement, the phrase ``this text'' refers to portions
12.\" of the system documentation.
13.\"
14.\" Portions of this text are reprinted and reproduced in electronic form
15.\" in the SunOS Reference Manual, from IEEE Std 1003.1, 2004 Edition,
16.\" Standard for Information Technology -- Portable Operating System
17.\" Interface (POSIX), The Open Group Base Specifications Issue 6,
18.\" Copyright (C) 2001-2004 by the Institute of Electrical and Electronics
19.\" Engineers, Inc and The Open Group.  In the event of any discrepancy
20.\" between these versions and the original IEEE and The Open Group
21.\" Standard, the original IEEE and The Open Group Standard is the referee
22.\" document.  The original Standard can be obtained online at
23.\" http://www.opengroup.org/unix/online.html.
24.\"
25.\" This notice shall appear on any product containing this material.
26.\"
27.\" The contents of this file are subject to the terms of the
28.\" Common Development and Distribution License (the "License").
29.\" You may not use this file except in compliance with the License.
30.\"
31.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
32.\" or http://www.opensolaris.org/os/licensing.
33.\" See the License for the specific language governing permissions
34.\" and limitations under the License.
35.\"
36.\" When distributing Covered Code, include this CDDL HEADER in each
37.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
38.\" If applicable, add the following below this CDDL HEADER, with the
39.\" fields enclosed by brackets "[]" replaced with your own identifying
40.\" information: Portions Copyright [yyyy] [name of copyright owner]
41.\"
42.\"
43.\" Portions Copyright (c) 1995 IEEE.  All Rights Reserved.
44.\" Copyright (c) 2001, The IEEE and The Open Group.  All Rights Reserved.
45.\" Copyright (c) 2007, Sun Microsystems, Inc.  All Rights Reserved.
46.\" Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
47.\" Copyright 2026 Oxide Computer Company
48.\"
49.Dd April 19, 2026
50.Dt MUTEX_INIT 3C
51.Os
52.Sh NAME
53.Nm mutex_init ,
54.Nm mutex_lock ,
55.Nm mutex_trylock ,
56.Nm mutex_unlock ,
57.Nm mutex_enter ,
58.Nm mutex_exit ,
59.Nm mutex_consistent ,
60.Nm mutex_destroy
61.Nd mutual exclusion locks
62.Sh LIBRARY
63.Lb libc
64.Sh SYNOPSIS
65.In thread.h
66.In synch.h
67.Ft int
68.Fo mutex_init
69.Fa "mutex_t *mp"
70.Fa "int type"
71.Fa "void *arg"
72.Fc
73.Ft int
74.Fo mutex_lock
75.Fa "mutex_t *mp"
76.Fc
77.Ft int
78.Fo mutex_trylock
79.Fa "mutex_t *mp"
80.Fc
81.Ft int
82.Fo mutex_unlock
83.Fa "mutex_t *mp"
84.Fc
85.Ft void
86.Fo mutex_enter
87.Fa "mutex_t *mp"
88.Fc
89.Ft void
90.Fo mutex_exit
91.Fa "mutex_t *mp"
92.Fc
93.Ft int
94.Fo mutex_consistent
95.Fa "mutex_t *mp"
96.Fc
97.Ft int
98.Fo mutex_destroy
99.Fa "mutex_t *mp"
100.Fc
101.Sh DESCRIPTION
102Mutual exclusion locks
103.Pq mutexes
104prevent multiple threads from simultaneously executing critical sections of code
105that access shared data
106.Pq that is, mutexes are used to serialize the execution of threads .
107All mutexes must be global.
108A successful call for a mutex lock by way of
109.Fn mutex_lock
110will cause another thread that is also trying to lock the same mutex to block
111until the owner thread unlocks it by way of
112.Fn mutex_unlock .
113Threads within the same process or within other processes can share mutexes.
114.Pp
115Mutexes can synchronize threads within the same process or in other processes.
116Mutexes can be used to synchronize threads between processes if the mutexes are
117allocated in writable memory and shared among the cooperating processes
118.Po
119see
120.Xr mmap 2
121.Pc ,
122and have been initialized for this task.
123.Ss "Initialize"
124Mutexes are either intra-process or inter-process, depending upon the argument
125passed implicitly or explicitly to the initialization of that mutex.
126A statically allocated mutex does not need to be explicitly initialized; by
127default, a statically allocated mutex is initialized with all zeros and its
128scope is set to be within the calling process.
129.Pp
130For inter-process synchronization, a mutex needs to be allocated in memory
131shared between these processes.
132Since the memory for such a mutex must be allocated dynamically, the mutex needs
133to be explicitly initialized using
134.Fn mutex_init .
135.Pp
136The
137.Fn mutex_init
138function initializes the mutex referenced by
139.Fa mp
140with the type specified by
141.Fa type .
142Upon successful initialization the state of the mutex becomes initialized and
143unlocked.
144Only the attribute type
145.Dv LOCK_PRIO_PROTECT
146uses
147.Fa arg .
148The
149.Fa type
150argument must be one of the following:
151.Bl -tag -width Dv
152.It Dv USYNC_THREAD
153The mutex can synchronize threads only in this process.
154.It Dv USYNC_PROCESS
155The mutex can synchronize threads in this process and other processes.
156The object initialized with this attribute must be allocated in memory shared
157between processes, either in System V shared memory
158.Po
159see
160.Xr shmop 2
161.Pc
162or in memory mapped to a file
163.Po
164see
165.Xr mmap 2
166.Pc .
167If the object is not allocated in such shared memory, it will not be shared
168between processes.
169.El
170.Pp
171The
172.Fa type
173argument can be augmented by the bitwise-inclusive-OR of zero or more of the
174following flags:
175.Bl -tag -width Dv
176.It Dv LOCK_ROBUST
177The mutex can synchronize threads robustly.
178At the time of thread or process death, either by calling
179.Xr thr_exit 3C
180or
181.Xr exit 2
182or due to process abnormal termination, the lock is unlocked if is held by the
183thread or process.
184The next owner of the mutex will acquire it with an error return of
185.Er EOWNERDEAD .
186The application must always check the return value from
187.Fn mutex_lock
188for a mutex of this type.
189The new owner of this mutex should then attempt to make the state protected by
190the mutex consistent, since this state could have been left inconsistent when
191the last owner died.
192If the new owner is able to make the state consistent, it should call
193.Fn mutex_consistent
194to restore the state of the mutex and then unlock the mutex.
195All subsequent calls to
196.Fn mutex_lock
197will then behave normally.
198Only the new owner can make the mutex consistent.
199If for any reason the new owner is not able to make the state consistent, it
200should not call
201.Fn mutex_consistent
202but should simply unlock the mutex.
203All waiting processes will be awakened and all subsequent calls to
204.Fn mutex_lock
205will fail in acquiring the mutex with an error value of
206.Er ENOTRECOVERABLE .
207If the thread or process that acquired the lock with
208.Er EOWNERDEAD
209terminates without unlocking the mutex, the next owner will acquire the lock
210with an error value of
211.Er EOWNERDEAD .
212.Pp
213The memory for the object to be initialized with this attribute must be zeroed
214before initialization.
215Any thread or process interested in the robust lock can call
216.Fn mutex_init
217to potentially initialize it, provided that all such callers of
218.Fn mutex_init
219specify the same set of attribute flags.
220In this situation, if
221.Fn mutex_init
222is called on a previously initialized robust mutex,
223.Fn mutex_init
224will not reinitialize the mutex and will return the error value
225.Er EBUSY .
226.It Dv LOCK_RECURSIVE
227A thread attempting to relock this mutex without first unlocking it will
228succeed in locking the mutex.
229The mutex must be unlocked as many times as it is locked.
230.It Dv LOCK_ERRORCHECK
231Unless
232.Dv LOCK_RECURSIVE
233is also set, a thread attempting to relock this mutex without first unlocking it
234will return with an error rather than deadlocking itself.
235A thread attempting to unlock this mutex without first owning it will return
236with an error.
237.It Dv LOCK_PRIO_INHERIT
238When a thread is blocking higher priority threads because of owning one or more
239mutexes with the
240.Dv LOCK_PRIO_INHERIT
241attribute, it executes at the higher of its priority or the priority of the
242highest priority thread waiting on any of the mutexes owned by this thread and
243initialized with this attribute.
244.It Dv LOCK_PRIO_PROTECT
245When a thread owns one or more mutexes initialized with the
246.Dv LOCK_PRIO_PROTECT
247attribute, it executes at the higher of its priority or the highest of the
248priority ceilings of all the mutexes owned by this thread and initialized with
249this attribute, regardless of whether other threads are blocked on any of these
250mutexes.
251When this attribute is specified,
252.Fa arg
253must point to an
254.Ft int
255containing the priority ceiling.
256.El
257.Pp
258See
259.Xr pthread_mutexattr_getrobust 3C
260for more information about robust mutexes.
261The
262.Dv LOCK_ROBUST
263attribute is the same as the POSIX
264.Dv PTHREAD_MUTEX_ROBUST
265attribute.
266.Pp
267See
268.Xr pthread_mutexattr_settype 3C
269for more information on recursive and error checking mutex types.
270The combination
271.Po
272.Dv LOCK_RECURSIVE
273|
274.Dv LOCK_ERRORCHECK
275.Pc
276is the same as the POSIX
277.Dv PTHREAD_MUTEX_RECURSIVE
278type.
279By itself,
280.Dv LOCK_ERRORCHECK
281is the same as the POSIX
282.Dv PTHREAD_MUTEX_ERRORCHECK
283type.
284.Pp
285The
286.Dv LOCK_PRIO_INHERIT
287attribute is the same as the POSIX
288.Dv PTHREAD_PRIO_INHERIT
289attribute.
290The
291.Dv LOCK_PRIO_PROTECT
292attribute is the same as the POSIX
293.Dv PTHREAD_PRIO_PROTECT
294attribute.
295See
296.Xr pthread_mutexattr_getprotocol 3C ,
297.Xr pthread_mutexattr_getprioceiling 3C ,
298and
299.Xr pthread_mutex_getprioceiling 3C
300for a full discussion.
301The
302.Dv LOCK_PRIO_INHERIT
303and
304.Dv LOCK_PRIO_PROTECT
305attributes are mutually exclusive.
306Specifying both of these attributes causes
307.Fn mutex_init
308to
309fail with
310.Er EINVAL .
311.Pp
312Initializing mutexes can also be accomplished by allocating in zeroed memory
313.Pq default ,
314in which case a
315.Fa type
316of
317.Dv USYNC_THREAD
318is assumed.
319In general, the following rules apply to mutex initialization:
320.Bl -bullet
321.It
322The same mutex must not be simultaneously initialized by multiple threads.
323.It
324A mutex lock must not be reinitialized while in use by other threads.
325.El
326.Pp
327These rules do not apply to
328.Dv LOCK_ROBUST
329mutexes.
330See the description for
331.Dv LOCK_ROBUST
332above.
333If default mutex attributes are used, the macro
334.Dv DEFAULTMUTEX
335can be used to initialize mutexes that are statically allocated.
336.Pp
337Default mutex initialization
338.Pq intra-process :
339.Bd -literal -offset indent
340mutex_t mp;
341mutex_init(&mp, USYNC_THREAD, NULL);
342.Ed
343.Pp
344or
345.Bd -literal -offset indent
346mutex_t mp = DEFAULTMUTEX;
347.Ed
348.Pp
349Customized mutex initialization
350.Pq inter-process :
351.Bd -literal -offset indent
352mutex_init(&mp, USYNC_PROCESS, NULL);
353.Ed
354.Pp
355Customized mutex initialization
356.Pq inter-process robust :
357.Bd -literal -offset indent
358mutex_init(&mp, USYNC_PROCESS | LOCK_ROBUST, NULL);
359.Ed
360.Pp
361Statically allocated mutexes can also be initialized with macros specifying
362.Dv LOCK_RECURSIVE
363and/or
364.Dv LOCK_ERRORCHECK :
365.Bd -literal -offset indent
366mutex_t mp = RECURSIVEMUTEX;
367.Ed
368.Pp
369Same as
370.Po
371.Dv USYNC_THREAD
372|
373.Dv LOCK_RECURSIVE
374.Pc
375.Bd -literal -offset indent
376mutex_t mp = ERRORCHECKMUTEX;
377.Ed
378.Pp
379Same as
380.Po
381.Dv USYNC_THREAD
382|
383.Dv LOCK_ERRORCHECK
384.Pc
385.Bd -literal -offset indent
386mutex_t mp = RECURSIVE_ERRORCHECKMUTEX;
387.Ed
388.Pp
389Same as
390.Po
391.Dv USYNC_THREAD
392|
393.Dv LOCK_RECURSIVE
394|
395.Dv LOCK_ERRORCHECK
396.Pc
397.Pp
398When working in an intra-process context, it is always recommended to use error
399checking mutexes and use the mutex lock and unlock variants
400.Fn mutex_enter
401and
402.Fn mutex_exit .
403These simplify the error checking conditions and will terminate a process on any
404cases an error would have been returned, similar to the operation of the
405kernel's
406.Xr mutex_enter 9F
407and
408.Xr mutex_exit 9F .
409.Ss "Lock and Unlock"
410A critical section of code is enclosed by the call to lock the mutex and the
411call to unlock the mutex to protect it from simultaneous access by multiple
412threads.
413Only one thread at a time may possess mutually exclusive access to the critical
414section of code that is enclosed by the mutex-locking call and the
415mutex-unlocking call, whether the mutex's scope is intra-process or
416inter-process.
417A thread calling to lock the mutex either gets exclusive access to the code
418starting from the successful locking until its call to unlock the mutex, or it
419waits until the mutex is unlocked by the thread that locked it.
420.Pp
421Mutexes have ownership, unlike semaphores.
422Although any thread, within the scope of a mutex, can get an unlocked mutex and
423lock access to the same critical section of code, only the thread that locked a
424mutex should unlock it.
425.Pp
426If a thread waiting for a mutex receives a signal, upon return from the signal
427handler, the thread resumes waiting for the mutex as if there was no interrupt.
428A mutex protects code, not data; therefore, strongly bind a mutex  with the data
429by putting both within the same structure, or at least within the same
430procedure.
431.Pp
432A call to
433.Fn mutex_lock
434locks the mutex object referenced by
435.Fa mp .
436If the mutex is already locked, the calling thread blocks until the mutex is
437freed; this will return with the mutex object referenced by
438.Fa mp
439in the locked state with the calling thread as its owner.
440If the current owner of a mutex tries to relock the mutex, it will result in
441deadlock.
442.Pp
443The
444.Fn mutex_trylock
445function is the same as
446.Fn mutex_lock ,
447except that if the mutex object referenced by
448.Fa mp
449is locked
450.Pq by any thread, including the current thread ,
451the call returns immediately with an error.
452.Pp
453The
454.Fn mutex_unlock
455function is called by the owner of the mutex object referenced by
456.Fa mp
457to release it.
458The mutex must be locked and the calling thread must be the one that last locked
459the mutex
460.Pq the owner .
461If there are threads blocked on the mutex object referenced by
462.Fa mp
463when
464.Fn mutex_unlock
465is called, the
466.Fa mp
467is freed, and the scheduling policy will determine which thread gets the mutex.
468If the calling thread is not the owner of the lock, no error status is returned,
469and the behavior of the program is undefined.
470.Pp
471The
472.Fn mutex_enter
473function is a variant of the
474.Fn mutex_lock
475function that returns void, meaning that it will perform all error checking and
476if any of the traditional mutex error conditions occur then the process will be
477terminated as though
478.Xr upanic 2
479or similar was called.
480All of the conditions of error checking mutexes are checked including trying
481to lock an uninitialized mutex, recursively locking a mutex that is not a
482recursive type, etc.
483The
484.Fn mutex_enter
485function is only suitable for
486.Dv USYNC_THREAD
487.Pq intra-process
488locks and the lock must have been initialized with the
489.Dv LOCK_ERRORCHECK
490attribute
491.Po
492or the
493.Dv ERRORCHECKMUTEX
494static initializer
495.Pc .
496If
497.Fa mp
498was not initialized as an error-checking mutex then that is treated as a fatal
499error when using
500.Fn mutex_enter .
501.Pp
502The
503.Fn mutex_exit
504function is a variant of the
505.Fn mutex_unlock
506function that returns void, meaning that it will perform all error checking and
507if any of the traditional mutex error conditions occur then the process will be
508terminated as though
509.Xr upanic 2
510or similar was called.
511All of the conditions of error checking mutexes are checked including trying to
512unlock a mutex that is not currently locked or where the calling thread is not
513the owner.
514The
515.Fn mutex_exit
516function is only suitable for
517.Dv USYNC_THREAD
518.Pq intra-process
519locks and the lock must have been initialized with the
520.Dv LOCK_ERRORCHECK
521attribute
522.Po
523or the
524.Dv ERRORCHECKMUTEX
525static initializer
526.Pc .
527If
528.Fa mp
529was not initialized as an error-checking mutex then that is treated as a fatal
530error when using
531.Fn mutex_exit .
532.Pp
533The
534.Fn mutex_enter
535and
536.Fn mutex_exit
537functions are modeled after the kernel's
538.Xr mutex_enter 9F
539and
540.Xr mutex_exit 9F
541functions.
542Using
543.Fn mutex_enter
544and
545.Fn mutex_exit
546is recommended over
547.Fn mutex_lock
548and
549.Fn mutex_unlock
550as most applications do not properly check or handle error conditions and
551terminating a process that has encountered programmer error is generally
552preferable to just sitting there deadlocked waiting for an administrator to
553determine that this has happened and kill the process.
554When these conditions are encountered, a core file will be generated subject to
555the
556.Xr coreadm 8
557settings.
558.Ss "Destroy"
559The
560.Fn mutex_destroy
561function destroys the mutex object referenced by
562.Fa mp .
563The mutex object becomes uninitialized.
564The space used by the destroyed mutex variable is not freed.
565It needs to be explicitly reclaimed.
566.Sh RETURN VALUES
567Upon successful completion, the
568.Fn mutex_init ,
569.Fn mutex_lock ,
570.Fn mutex_trylock ,
571.Fn mutex_unlock ,
572.Fn mutex_consistent ,
573and
574.Fn mutex_destroy
575functions return
576.Sy 0 .
577Otherwise, an error number is returned.
578.Sh EXAMPLES
579.Ss "Single Gate"
580The following example uses one global mutex as a gate-keeper to permit each
581thread exclusive sequential access to the code within the user-defined
582function "change_global_data".
583This type of synchronization will protect the state of shared data, but it also
584prohibits parallelism.
585.Bd -literal -offset 2n
586/* gcc thisfile.c */
587#define _REENTRANT
588#include <stdio.h>
589#include <thread.h>
590#define NUM_THREADS 12
591void *change_global_data(void *);     /*  for thr_create()   */
592main(int argc,char * argv[])    {
593       int i=0;
594       for (i=0; i< NUM_THREADS; i++)	{
595               thr_create(NULL, 0, change_global_data, NULL, 0, NULL);
596       }
597       while ((thr_join(NULL, NULL, NULL) == 0));
598}
599
600void * change_global_data(void *null){
601       static mutex_t   Global_mutex;
602       static int       Global_data = 0;
603       mutex_lock(&Global_mutex);
604       Global_data++;
605       sleep(1);
606       printf("%d is global data\en",Global_data);
607       mutex_unlock(&Global_mutex);
608       return NULL;
609}
610.Ed
611.Ss "Multiple Instruction Single Data"
612The previous example, the mutex, the code it owns, and the data it protects was
613enclosed in one function.
614The next example uses C++ features to accommodate many functions that use just
615one mutex to protect one data:
616.Bd -literal -offset 2n
617/* g++ thisfile.c use C++ to compile*/
618
619#define _REENTRANT
620#include <stdlib.h>
621#include <stdio.h>
622#include <thread.h>
623#include <errno.h>
624#include <iostream.h>
625#define NUM_THREADS 16
626void *change_global_data(void *);     /*  for thr_create()   */
627
628class Mutected {
629       private:
630               static mutex_t      Global_mutex;
631               static int          Global_data;
632       public:
633               static int          add_to_global_data(void);
634               static int          subtract_from_global_data(void);
635};
636
637int Mutected::Global_data = 0;
638mutex_t Mutected::Global_mutex;
639
640int Mutected::add_to_global_data()  {
641       mutex_lock(&Global_mutex);
642       Global_data++;
643       mutex_unlock(&Global_mutex);
644       return Global_data;
645}
646
647int Mutected::subtract_from_global_data()   {
648       mutex_lock(&Global_mutex);
649       Global_data--;
650       mutex_unlock(&Global_mutex);
651       return Global_data;
652}
653
654void
655main(int argc,char * argv[])  {
656       int i=0;
657       for (i=0;i< NUM_THREADS;i++)  {
658            thr_create(NULL,0,change_global_data,NULL,0,NULL);
659       }
660       while ((thr_join(NULL,NULL,NULL) == 0));
661}
662
663void * change_global_data(void *)	{
664       static int switcher = 0;
665       if ((switcher++ % 3) == 0)   /* one-in-three threads subtracts */
666               cout << Mutected::subtract_from_global_data() << endl;
667       else
668               cout << Mutected::add_to_global_data() << endl;
669       return NULL;
670}
671.Ed
672.Ss "Interprocess Locking"
673A mutex can protect data that is shared among processes.
674The mutex would need to be initialized as
675.Dv USYNC_PROCESS .
676One process initializes the process-shared mutex and writes it to a file to be
677mapped into memory by all cooperating processes
678.Po
679see
680.Xr mmap 2
681.Pc .
682Afterwards, other independent processes can run the same program
683.Pq whether concurrently or not
684and share mutex-protected data.
685.Bd -literal -offset 2n
686/* gcc thisfile.c */
687/* To execute, run the command line "a.out 0 &; a.out 1" */
688
689#define _REENTRANT
690#include <sys/types.h>
691#include <sys/mman.h>
692#include <sys/stat.h>
693#include <fcntl.h>
694#include <stdio.h>
695#include <thread.h>
696#define INTERPROCESS_FILE "ipc-sharedfile"
697#define NUM_ADDTHREADS 12
698#define NUM_SUBTRACTTHREADS 10
699#define INCREMENT '0'
700#define DECREMENT '1'
701typedef struct {
702               mutex_t     Interprocess_mutex;
703               int         Interprocess_data;
704} buffer_t;
705buffer_t *buffer;
706
707void *add_interprocess_data(), *subtract_interprocess_data();
708void create_shared_memory(), test_argv();
709int zeroed[sizeof(buffer_t)];
710int ipc_fd, i=0;
711
712void
713main(int argc,char * argv[]){
714    test_argv(argv[1]);
715
716    switch (*argv[1])  {
717    case INCREMENT:
718         /* Initializes the process-shared mutex */
719         /* Should be run prior to running a DECREMENT process */
720         create_shared_memory();
721         ipc_fd = open(INTERPROCESS_FILE, O_RDWR);
722         buffer = (buffer_t *)mmap(NULL, sizeof(buffer_t),
723             PROT_READ | PROT_WRITE, MAP_SHARED, ipc_fd, 0);
724         buffer->Interprocess_data = 0;
725         mutex_init(&buffer->Interprocess_mutex, USYNC_PROCESS,0);
726         for (i=0; i< NUM_ADDTHREADS; i++)
727         thr_create(NULL, 0, add_interprocess_data, argv[1],
728             0, NULL);
729         break;
730
731    case DECREMENT:
732         /* Should be run after the INCREMENT process has run. */
733         while(ipc_fd = open(INTERPROCESS_FILE, O_RDWR)) == -1)
734             sleep(1);
735         buffer = (buffer_t *)mmap(NULL, sizeof(buffer_t),
736             PROT_READ | PROT_WRITE, MAP_SHARED, ipc_fd, 0);
737         for (i=0; i< NUM_SUBTRACTTHREADS; i++)
738         thr_create(NULL, 0, subtract_interprocess_data, argv[1],
739             0, NULL);
740         break;
741    } /* end switch */
742
743    while ((thr_join(NULL,NULL,NULL) == 0));
744} /* end main */
745
746void *add_interprocess_data(char argv_1[]){
747    mutex_lock(&buffer->Interprocess_mutex);
748    buffer->Interprocess_data++;
749    sleep(2);
750    printf("%d is add-interprocess data, and %c is argv1\en",
751        buffer->Interprocess_data, argv_1[0]);
752    mutex_unlock(&buffer->Interprocess_mutex);
753    return NULL;
754}
755
756void *subtract_interprocess_data(char argv_1[])	{
757    mutex_lock(&buffer->Interprocess_mutex);
758    buffer->Interprocess_data--;
759    sleep(2);
760    printf("%d is subtract-interprocess data, and %c is argv1\en",
761        buffer->Interprocess_data, argv_1[0]);
762    mutex_unlock(&buffer->Interprocess_mutex);
763    return NULL;
764}
765
766void create_shared_memory(){
767    int i;
768    ipc_fd = creat(INTERPROCESS_FILE, O_CREAT | O_RDWR );
769    for (i=0; i<sizeof(buffer_t); i++){
770        zeroed[i] = 0;
771        write(ipc_fd, &zeroed[i],2);
772    }
773    close(ipc_fd);
774    chmod(INTERPROCESS_FILE, S_IRWXU | S_IRWXG | S_IRWXO);
775}
776
777void test_argv(char argv1[])   {
778    if (argv1 == NULL)   {
779    printf("use 0 as arg1 for initial process\en \e
780    or use 1 as arg1 for the second process\en");
781    exit(NULL);
782    }
783}
784.Ed
785.Ss "Interprocess Robust Locking"
786A mutex can protect data that is shared among processes robustly.
787The mutex would need to be initialized as
788.Dv USYNC_PROCESS | LOCK_ROBUST .
789One process initializes the robust process-shared mutex and writes it to a file
790to be mapped into memory by all cooperating processes
791.Po
792see
793.Xr mmap 2
794.Pc .
795Afterwards, other independent processes can run the same program
796.Pq whether concurrently or not
797and share mutex-protected data.
798.Pp
799The following example shows how to use a
800.Dv USYNC_PROCESS | LOCK_ROBUST
801type mutex.
802.Bd -literal -offset 2n
803/* gcc thisfile.c */
804 /* To execute, run the command line "a.out & a.out 1" */
805 #include <sys/types.h>
806 #include <sys/mman.h>
807 #include <fcntl.h>
808 #include <stdio.h>
809 #include <thread.h>
810 #define INTERPROCESS_FILE "ipc-sharedfile"
811 typedef struct {
812           mutex_t   Interprocess_mutex;
813           int       Interprocess_data;
814 } buffer_t;
815 buffer_t *buffer;
816 int make_date_consistent();
817 void create_shared_memory();
818 int zeroed[sizeof(buffer_t)];
819 int ipc_fd, i=0;
820 main(int argc,char * argv[])  {
821     int rc;
822     if (argc > 1) {
823         while((ipc_fd = open(INTERPROCESS_FILE, O_RDWR)) == -1)
824             sleep(1);
825         buffer = (buffer_t *)mmap(NULL, sizeof(buffer_t),
826                   PROT_READ | PROT_WRITE, MAP_SHARED, ipc_fd, 0);
827         mutex_init(&buffer->Interprocess_mutex,
828                     USYNC_PROCESS | LOCK_ROBUST, 0);
829     } else {
830         create_shared_memory();
831         ipc_fd = open(INTERPROCESS_FILE, O_RDWR);
832         buffer = (buffer_t *)mmap(NULL, sizeof(buffer_t),
833               PROT_READ | PROT_WRITE, MAP_SHARED, ipc_fd, 0);
834         buffer->Interprocess_data = 0;
835         mutex_init(&buffer->Interprocess_mutex,
836                     USYNC_PROCESS | LOCK_ROBUST, 0);
837     }
838     for(;;) {
839         rc = mutex_lock(&buffer->Interprocess_mutex);
840         switch (rc) {
841             case EOWNERDEAD:
842               /*
843                * The lock is acquired.
844                * The last owner died holding the lock.
845                * Try to make the state associated with
846                * the mutex consistent.
847                * If successful, make the robust lock consistent.
848                */
849               if (make_data_consistent())
850                   mutex_consistent(&buffer->Interprocess_mutex);
851                   mutex_unlock(&buffer->Interprocess_mutex);
852                   break;
853             case ENOTRECOVERABLE:
854               /*
855                * The lock is not acquired.
856                * The last owner got the mutex with EOWNERDEAD
857                * and failed to make the data consistent.
858                * There is no way to recover, so just exit.
859                */
860               exit(1);
861             case 0:
862               /*
863                * There is no error - data is consistent.
864                * Do something with data.
865                */
866               mutex_unlock(&buffer->Interprocess_mutex);
867               break;
868        }
869   }
870} /* end main */
871void create_shared_memory() {
872      int i;
873      ipc_fd = creat(INTERPROCESS_FILE, O_CREAT | O_RDWR );
874      for (i=0; i<sizeof(buffer_t); i++) {
875           zeroed[i] = 0;
876           write(ipc_fd, &zeroed[i],2);
877      }
878      close(ipc_fd);
879      chmod(INTERPROCESS_FILE, S_IRWXU | S_IRWXG | S_IRWXO);
880 }
881
882 /* return 1 if able to make data consistent, otherwise 0. */
883 int make_data_consistent () {
884       buffer->Interprocess_data = 0;
885       return (1);
886 }
887.Ed
888.Ss "Dynamically Allocated Mutexes"
889The following example allocates and frees memory in which a mutex is embedded.
890.Bd -literal -offset 2n
891struct record {
892        int field1;
893        int field2;
894        mutex_t m;
895} *r;
896r = malloc(sizeof(struct record));
897mutex_init(&r->m, USYNC_THREAD, NULL);
898/*
899 * The fields in this record are accessed concurrently
900 * by acquiring the embedded lock.
901 */
902.Ed
903.Pp
904The thread execution in this example is as follows:
905.Bd -literal -offset 2n
906Thread 1 executes:                 Thread 2 executes:
907
908\&...                                ...
909mutex_lock(&r->m);                 mutex_lock(&r->m);
910r->field1++;                       localvar = r->field1;
911mutex_unlock(&r->m);               mutex_unlock(&r->m);
912\&...                                ...
913.Ed
914.Pp
915Later, when a thread decides to free the memory pointed to by
916.Fa r ,
917the thread should call
918.Fn mutex_destroy
919on the mutexes in this memory.
920.Pp
921In the following example, the main thread can do a
922.Xr thr_join 3C
923on both of the above threads.
924If there are no other threads using the memory in
925.Fa r ,
926the main thread can now safely free
927.Fa r :
928.Bd -literal -offset 2n
929for (i = 0; i < 2; i++)
930       thr_join(0, 0, 0);
931mutex_destroy(&r->m);   /* first destroy mutex */
932free(r);                /* then free memory */
933.Ed
934.Pp
935If the mutex is not destroyed, the program could have memory leaks.
936.Sh ERRORS
937The
938.Fn mutex_init
939function will fail if:
940.Bl -tag -width Er
941.It Er EINVAL
942The value specified by
943.Fa type
944is invalid, or the
945.Dv LOCK_PRIO_INHERIT
946and
947.Dv LOCK_PRIO_PROTECT
948attributes are both specified.
949.El
950.Pp
951The
952.Fn mutex_init
953function will fail for
954.Dv LOCK_ROBUST
955type mutex if:
956.Bl -tag -width Er
957.It Er EBUSY
958The mutex pointed to by
959.Fa mp
960was previously initialized and has not yet been destroyed.
961.It Er EINVAL
962The mutex pointed to by
963.Fa mp
964was previously initialized with a different set of attribute flags.
965.El
966.Pp
967The
968.Fn mutex_trylock
969function will fail if:
970.Bl -tag -width Er
971.It Er EBUSY
972The mutex pointed to by
973.Fa mp
974is already locked.
975.El
976.Pp
977The
978.Fn mutex_lock
979and
980.Fn mutex_trylock
981functions will fail for a
982.Dv LOCK_RECURSIVE
983mutex if:
984.Bl -tag -width Er
985.It Er EAGAIN
986The mutex could not be acquired because the maximum number of recursive locks
987for the mutex has been reached.
988.El
989.Pp
990The
991.Fn mutex_lock
992function will fail for a
993.Dv LOCK_ERRORCHECK
994and
995.No non- Ns Dv LOCK_RECURSIVE
996mutex if:
997.Bl -tag -width Er
998.It Er EDEADLK
999The caller already owns the mutex.
1000.El
1001.Pp
1002The
1003.Fn mutex_lock
1004function may fail for a
1005.No non- Ns Dv LOCK_ERRORCHECK
1006and
1007.No non- Ns Dv LOCK_RECURSIVE
1008mutex if:
1009.Bl -tag -width Er
1010.It Er EDEADLK
1011The caller already owns the mutex.
1012.El
1013.Pp
1014The
1015.Fn mutex_unlock
1016function will fail for a
1017.Dv LOCK_ERRORCHECK
1018mutex if:
1019.Bl -tag -width Er
1020.It Er EPERM
1021The caller does not own the mutex.
1022.El
1023.Pp
1024The
1025.Fn mutex_lock
1026or
1027.Fn mutex_trylock
1028functions will fail for
1029.Dv LOCK_ROBUST
1030type mutex if:
1031.Bl -tag -width Er
1032.It Er EOWNERDEAD
1033The last owner of this mutex died while holding the mutex.
1034This mutex is now owned by the caller.
1035The caller must now attempt to make the state protected by the mutex consistent.
1036If it is able to clean up the state, then it should restore the state of the
1037mutex by calling
1038.Fn mutex_consistent
1039and unlock the mutex.
1040Subsequent calls to
1041.Fn mutex_lock
1042will behave normally, as before.
1043If the caller is not able to clean up the state,
1044.Fn mutex_consistent
1045should not be called but the mutex should be unlocked.
1046Subsequent calls to
1047.Fn mutex_lock
1048will fail to acquire the mutex, returning with the error value
1049.Er ENOTRECOVERABLE .
1050If the owner who acquired the lock with
1051.Er EOWNERDEAD
1052dies, the next owner will acquire the lock with
1053.Er EOWNERDEAD .
1054.It Er ENOTRECOVERABLE
1055The mutex trying to be acquired was protecting the state that has been left
1056unrecoverable when the mutex's last owner could not make the state protected by
1057the mutex consistent.
1058The mutex has not been acquired.
1059This condition occurs when the lock was previously acquired with
1060.Er EOWNERDEAD
1061and the owner was not able to clean up the state and unlocked the mutex without
1062calling
1063.Fn mutex_consistent .
1064.El
1065.Pp
1066The
1067.Fn mutex_consistent
1068function will fail if:
1069.Bl -tag -width Er
1070.It Er EINVAL
1071The caller does not own the mutex or the mutex is not a
1072.Dv LOCK_ROBUST
1073mutex having an inconsistent state
1074.Pq Dv EOWNERDEAD .
1075.El
1076.Sh INTERFACE STABILITY
1077.Sy Committed
1078.Sh MT-Level
1079.Sy MT-Safe
1080.Sh SEE ALSO
1081.Xr mmap 2 ,
1082.Xr shmop 2 ,
1083.Xr pthread_mutex_getprioceiling 3C ,
1084.Xr pthread_mutex_init 3C ,
1085.Xr pthread_mutexattr_getprioceiling 3C ,
1086.Xr pthread_mutexattr_getprotocol 3C ,
1087.Xr pthread_mutexattr_getrobust 3C ,
1088.Xr pthread_mutexattr_gettype 3C ,
1089.Xr attributes 7 ,
1090.Xr mutex 7 ,
1091.Xr standards 7
1092.Sh NOTES
1093Previous releases of Solaris provided the
1094.Dv USYNC_PROCESS_ROBUST
1095mutex type.
1096This type is now deprecated but is still supported for source and binary
1097compatibility.
1098When passed to
1099.Fn mutex_init ,
1100it is transformed into
1101.Pq Dv USYNC_PROCESS | LOCK_ROBUST .
1102The former method for restoring a
1103.Dv USYNC_PROCESS_ROBUST
1104mutex to a consistent state was to reinitialize it by calling
1105.Fn mutex_init .
1106This method is still supported for source and binary compatibility, but the
1107proper method is to call
1108.Fn mutex_consistent .
1109.Pp
1110The
1111.Dv USYNC_PROCESS_ROBUST
1112type permitted an alternate error value,
1113.Er ELOCKUNMAPPED ,
1114to be returned by
1115.Fn mutex_lock
1116if the process containing a locked robust mutex unmapped the memory containing
1117the mutex or performed one of the
1118.Xr exec 2
1119functions.
1120The
1121.Er ELOCKUNMAPPED
1122error value implies all of the consequences of the
1123.Er EOWNERDEAD
1124error value and as such is just a synonym for
1125.Er EOWNERDEAD .
1126For full source and binary compatibility, the
1127.Er ELOCKUNMAPPED
1128error value is still returned from
1129.Fn mutex_lock
1130in these circumstances, but only if the mutex was initialized with the
1131.Dv USYNC_PROCESS_ROBUST
1132type.
1133Otherwise,
1134.Er EOWNERDEAD
1135is returned in these circumstances.
1136.Pp
1137The
1138.Fn mutex_lock ,
1139.Fn mutex_unlock ,
1140and
1141.Fn mutex_trylock
1142functions do not validate the mutex type.
1143An uninitialized mutex or a mutex with an invalid type does not return
1144.Er EINVAL .
1145Interfaces for mutexes with an invalid type have unspecified behavior.
1146.Pp
1147Uninitialized mutexes that are allocated locally could contain junk data.
1148Such mutexes need to be initialized using
1149.Fn mutex_init .
1150.Pp
1151By default, if multiple threads are waiting for a mutex, the order of
1152acquisition is undefined.
1153