xref: /illumos-gate/usr/src/lib/sun_fc/common/Lockable.cc (revision ed093b41a93e8563e6e1e5dae0768dda2a7bcc27)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * Copyright 2019 RackTop Systems.
26  */
27 
28 
29 #include "Lockable.h"
30 #include <iostream>
31 #include <cstdio>
32 #include <cerrno>
33 #include <unistd.h>
34 #include <cstring>
35 
36 using namespace std;
37 
38 #define	    DEADLOCK_WARNING 10
39 #define	    LOCK_SLEEP 1
40 
41 /**
42  * @memo	    Create a lockable instance and initialize internal locks
43  */
44 Lockable::Lockable() {
45 	if (pthread_mutex_init(&mutex, NULL)) {
46 	}
47 }
48 
49 /**
50  * @memo	    Free up a lockable instance
51  */
52 Lockable::~Lockable() {
53 	if (pthread_mutex_destroy(&mutex)) {
54 	}
55 }
56 
57 /**
58  * @memo	    Unlock the instance
59  * @precondition    This thread must have locked the instance
60  * @postcondition   The instance will be unlocked
61  */
62 void Lockable::unlock() {
63 	unlock(&mutex);
64 }
65 
66 /**
67  * @memo	    Unlock a given mutex lock
68  * @precondition    The lock must be held by this thread
69  * @postcondition   The lock will be released
70  * @param	    myMutex The lock to unlock
71  */
72 void Lockable::unlock(pthread_mutex_t *myMutex) {
73 	pthread_mutex_unlock(myMutex);
74 }
75 
76 /**
77  * @memo	    Lock the instance
78  * @postcondition   The lock will be held by this thread.
79  */
80 void Lockable::lock() {
81 	lock(&mutex);
82 }
83 
84 /**
85  * @memo	    Lock the given mutex lock
86  * @postcondition   The lock will be held by this thread
87  * @param	    myMutex The mutex lock to take
88  */
89 void Lockable::lock(pthread_mutex_t *myMutex) {
90 	int status;
91 	int loop = 0;
92 	do {
93 	    loop++;
94 	    status = pthread_mutex_trylock(myMutex);
95 	    if (status) {
96 		switch (pthread_mutex_trylock(myMutex)) {
97 		case EFAULT:
98 		    cerr << "Lock failed: Fault" << endl;
99 		    break;
100 		case EINVAL:
101 		    cerr << "Lock failed: Invalid" << endl;
102 		    break;
103 		case EBUSY:
104 		    if (loop > DEADLOCK_WARNING) {
105 			cerr << "Lock failed: Deadlock" << endl;
106 		    }
107 		    break;
108 		case EOWNERDEAD:
109 		    cerr << "Lock failed: Owner died" << endl;
110 		    break;
111 		case ELOCKUNMAPPED:
112 		    cerr << "Lock failed: Unmapped" << endl;
113 		    break;
114 		case ENOTRECOVERABLE:
115 		    cerr << "Lock failed: not recoverable" << endl;
116 		    /* FALLTHROUGH */
117 		default:
118 		    if (loop > DEADLOCK_WARNING) {
119 			cerr << "Lock failed: " <<strerror(status) << endl;
120 			break;
121 		    }
122 		}
123 	    } else {
124 		break; // Lock taken succesfully
125 	    }
126 	    sleep(LOCK_SLEEP);
127 	} while (status);
128 }
129