1 /*
2  * locks.c
3  *
4  * Code for abstracting locks in IPMI
5  *
6  * Author: MontaVista Software, Inc.
7  *         Corey Minyard <minyard@mvista.com>
8  *         source@mvista.com
9  *
10  * Copyright 2004,2005 MontaVista Software Inc.
11  *
12  * This software is available to you under a choice of one of two
13  * licenses.  You may choose to be licensed under the terms of the GNU
14  * Lesser General Public License (GPL) Version 2 or the modified BSD
15  * license below.  The following disclamer applies to both licenses:
16  *
17  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
18  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
23  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
26  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * GNU Lesser General Public Licence
29  *
30  *  This program is free software; you can redistribute it and/or
31  *  modify it under the terms of the GNU Lesser General Public License
32  *  as published by the Free Software Foundation; either version 2 of
33  *  the License, or (at your option) any later version.
34  *
35  *  You should have received a copy of the GNU Lesser General Public
36  *  License along with this program; if not, write to the Free
37  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
38  *
39  * Modified BSD Licence
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  *
45  *   1. Redistributions of source code must retain the above copyright
46  *      notice, this list of conditions and the following disclaimer.
47  *   2. Redistributions in binary form must reproduce the above
48  *      copyright notice, this list of conditions and the following
49  *      disclaimer in the documentation and/or other materials provided
50  *      with the distribution.
51  *   3. The name of the author may not be used to endorse or promote
52  *      products derived from this software without specific prior
53  *      written permission.
54  */
55 
56 #include <stdlib.h>
57 #include <errno.h>
58 
59 #include <OpenIPMI/ipmi_debug.h>
60 
61 #include <OpenIPMI/internal/ipmi_malloc.h>
62 #include <OpenIPMI/internal/ipmi_locks.h>
63 
64 struct ipmi_lock_s
65 {
66     os_hnd_lock_t *ll_lock;
67     os_handler_t  *os_hnd;
68 };
69 
70 int i__ipmi_debug_locks = 0;
71 
72 int
ipmi_create_lock_os_hnd(os_handler_t * os_hnd,ipmi_lock_t ** new_lock)73 ipmi_create_lock_os_hnd(os_handler_t *os_hnd, ipmi_lock_t **new_lock)
74 {
75     ipmi_lock_t *lock;
76     int         rv;
77 
78     lock = ipmi_mem_alloc(sizeof(*lock));
79     if (!lock)
80 	return ENOMEM;
81 
82     lock->os_hnd = os_hnd;
83     if (lock->os_hnd && lock->os_hnd->create_lock) {
84 	rv = lock->os_hnd->create_lock(lock->os_hnd, &(lock->ll_lock));
85 	if (rv) {
86 	    ipmi_mem_free(lock);
87 	    return rv;
88 	}
89     } else {
90 	lock->ll_lock = NULL;
91     }
92 
93     *new_lock = lock;
94 
95     return 0;
96 }
97 
ipmi_destroy_lock(ipmi_lock_t * lock)98 void ipmi_destroy_lock(ipmi_lock_t *lock)
99 {
100     if (lock->ll_lock)
101 	lock->os_hnd->destroy_lock(lock->os_hnd, lock->ll_lock);
102     ipmi_mem_free(lock);
103 }
104 
ipmi_lock(ipmi_lock_t * lock)105 void ipmi_lock(ipmi_lock_t *lock)
106 {
107     if (lock->ll_lock)
108 	lock->os_hnd->lock(lock->os_hnd, lock->ll_lock);
109 }
110 
ipmi_unlock(ipmi_lock_t * lock)111 void ipmi_unlock(ipmi_lock_t *lock)
112 {
113     if (lock->ll_lock)
114 	lock->os_hnd->unlock(lock->os_hnd, lock->ll_lock);
115 }
116 
117 struct ipmi_rwlock_s
118 {
119     os_hnd_rwlock_t *ll_lock;
120     os_handler_t  *os_hnd;
121 };
122 
123 int
ipmi_create_rwlock_os_hnd(os_handler_t * os_hnd,ipmi_rwlock_t ** new_lock)124 ipmi_create_rwlock_os_hnd(os_handler_t *os_hnd, ipmi_rwlock_t **new_lock)
125 {
126     ipmi_rwlock_t *lock;
127     int         rv;
128 
129     lock = ipmi_mem_alloc(sizeof(*lock));
130     if (!lock)
131 	return ENOMEM;
132 
133     lock->os_hnd = os_hnd;
134     if (lock->os_hnd && lock->os_hnd->create_lock) {
135 	rv = lock->os_hnd->create_rwlock(lock->os_hnd, &(lock->ll_lock));
136 	if (rv) {
137 	    ipmi_mem_free(lock);
138 	    return rv;
139 	}
140     } else {
141 	lock->ll_lock = NULL;
142     }
143 
144     *new_lock = lock;
145 
146     return 0;
147 }
148 
ipmi_destroy_rwlock(ipmi_rwlock_t * lock)149 void ipmi_destroy_rwlock(ipmi_rwlock_t *lock)
150 {
151     if (lock->ll_lock)
152 	lock->os_hnd->destroy_rwlock(lock->os_hnd, lock->ll_lock);
153     ipmi_mem_free(lock);
154 }
155 
ipmi_rwlock_read_lock(ipmi_rwlock_t * lock)156 void ipmi_rwlock_read_lock(ipmi_rwlock_t *lock)
157 {
158     if (lock->ll_lock)
159 	lock->os_hnd->read_lock(lock->os_hnd, lock->ll_lock);
160 }
161 
ipmi_rwlock_read_unlock(ipmi_rwlock_t * lock)162 void ipmi_rwlock_read_unlock(ipmi_rwlock_t *lock)
163 {
164     if (lock->ll_lock)
165 	lock->os_hnd->read_unlock(lock->os_hnd, lock->ll_lock);
166 }
167 
ipmi_rwlock_write_lock(ipmi_rwlock_t * lock)168 void ipmi_rwlock_write_lock(ipmi_rwlock_t *lock)
169 {
170     if (lock->ll_lock)
171 	lock->os_hnd->write_lock(lock->os_hnd, lock->ll_lock);
172 }
173 
ipmi_rwlock_write_unlock(ipmi_rwlock_t * lock)174 void ipmi_rwlock_write_unlock(ipmi_rwlock_t *lock)
175 {
176     if (lock->ll_lock)
177 	lock->os_hnd->write_unlock(lock->os_hnd, lock->ll_lock);
178 }
179 
180 #ifdef IPMI_CHECK_LOCKS
181 /* Set a breakpoint here to detect locking errors. */
182 void
ipmi_report_lock_error(os_handler_t * handler,char * str)183 ipmi_report_lock_error(os_handler_t *handler, char *str)
184 {
185     handler->log(handler, IPMI_LOG_WARNING, "%s", str);
186 }
187 
188 void
ipmi_check_lock(ipmi_lock_t * lock,char * str)189 ipmi_check_lock(ipmi_lock_t *lock, char *str)
190 {
191     if ((!DEBUG_LOCKS) || (!lock) || (!lock->ll_lock))
192 	return;
193 
194     if (! lock->os_hnd->is_locked(lock->os_hnd, lock->ll_lock))
195 	IPMI_REPORT_LOCK_ERROR(lock->os_hnd, str);
196 }
197 #endif
198