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