1 #define MODULE_LOG_PREFIX "lock"
4 #include "oscam-lock.h"
5 #include "oscam-time.h"
12 void cs_lock_create(const char *n
, CS_MUTEX_LOCK
*l
, const char *name
, uint32_t timeout_ms
)
14 memset(l
, 0, sizeof(CS_MUTEX_LOCK
));
15 l
->timeout
= timeout_ms
/ 1000;
17 SAFE_MUTEX_INIT_R(&l
->lock
, NULL
, n
);
18 __cs_pthread_cond_init(n
, &l
->writecond
);
19 __cs_pthread_cond_init(n
, &l
->readcond
);
20 #ifdef WITH_MUTEXDEBUG
21 cs_log_dbg(D_TRACE
, "lock %s created", name
);
28 void cs_lock_create_nolog(const char *n
, CS_MUTEX_LOCK
*l
, const char *name
, uint32_t timeout_ms
)
30 memset(l
, 0, sizeof(CS_MUTEX_LOCK
));
31 l
->timeout
= timeout_ms
/ 1000;
33 SAFE_MUTEX_INIT_NOLOG_R(&l
->lock
, NULL
, n
);
34 __cs_pthread_cond_init(n
, &l
->writecond
);
35 __cs_pthread_cond_init(n
, &l
->readcond
);
36 #ifdef WITH_MUTEXDEBUG
37 cs_log_dbg(D_TRACE
, "lock %s created", name
);
41 void cs_lock_destroy(const char *pn
, CS_MUTEX_LOCK
*l
)
43 if(!l
|| !l
->name
|| l
->flag
) { return; }
45 cs_rwlock_int(pn
, l
, WRITELOCK
);
47 const char *old_name
= l
->name
;
49 l
->name
= NULL
; // No new locks!
50 cs_rwunlock_int(pn
, l
, WRITELOCK
);
52 // Do not destroy when having pending locks!
53 int32_t n
= (l
->timeout
/ 10) + 2;
54 while((--n
> 0) && (l
->writelock
|| l
->readlock
)) { cs_sleepms(10); }
56 cs_rwlock_int(pn
, l
, WRITELOCK
);
57 l
->flag
++; // No new unlocks!
58 cs_rwunlock_int(pn
, l
, WRITELOCK
);
61 if(!n
&& old_name
!= LOG_LIST
)
62 { cs_log("WARNING lock %s destroy timed out.", old_name
); }
65 pthread_mutex_destroy(&l
->lock
);
66 pthread_cond_destroy(&l
->writecond
);
67 pthread_cond_destroy(&l
->readcond
);
68 #ifdef WITH_MUTEXDEBUG
69 cs_log_dbg(D_TRACE
, "lock %s destroyed", l
->name
);
73 void cs_rwlock_int(const char *n
, CS_MUTEX_LOCK
*l
, int8_t type
)
78 if(!l
|| !l
->name
|| l
->flag
)
81 SAFE_MUTEX_LOCK_R(&l
->lock
, n
);
83 add_ms_to_timespec(&ts
, l
->timeout
* 1000);
84 ts
.tv_nsec
= 0; // 100% resemble previous code, I consider it wrong
88 // if read- or writelock is busy, wait for unlock
89 if(l
->writelock
> 1 || l
->readlock
> 0)
90 { ret
= pthread_cond_timedwait(&l
->writecond
, &l
->lock
, &ts
); }
95 // if writelock is busy, wait for unlock
97 { ret
= pthread_cond_timedwait(&l
->readcond
, &l
->lock
, &ts
); }
102 // lock wasn't returned within time, assume locking thread to
103 // be stuck or finished, so enforce lock.
104 l
->writelock
= (type
== WRITELOCK
) ? 1 : 0;
105 l
->readlock
= (type
== WRITELOCK
) ? 0 : 1;
107 if(l
->name
!= LOG_LIST
)
108 { cs_log("WARNING lock %s (%s) timed out.", l
->name
, (type
== WRITELOCK
) ? "WRITELOCK" : "READLOCK"); }
112 SAFE_MUTEX_UNLOCK_R(&l
->lock
, n
);
113 #ifdef WITH_MUTEXDEBUG
114 //cs_log_dbg(D_TRACE, "lock %s locked", l->name);
119 void cs_rwlock_int_nolog(const char *n
, CS_MUTEX_LOCK
*l
, int8_t type
)
124 if(!l
|| !l
->name
|| l
->flag
)
127 SAFE_MUTEX_LOCK_NOLOG_R(&l
->lock
, n
);
129 add_ms_to_timespec(&ts
, l
->timeout
* 1000);
130 ts
.tv_nsec
= 0; // 100% resemble previous code, I consider it wrong
131 if(type
== WRITELOCK
)
134 // if read- or writelock is busy, wait for unlock
135 if(l
->writelock
> 1 || l
->readlock
> 0)
136 { ret
= pthread_cond_timedwait(&l
->writecond
, &l
->lock
, &ts
); }
141 // if writelock is busy, wait for unlock
143 { ret
= pthread_cond_timedwait(&l
->readcond
, &l
->lock
, &ts
); }
148 // lock wasn't returned within time, assume locking thread to
149 // be stuck or finished, so enforce lock.
150 l
->writelock
= (type
== WRITELOCK
) ? 1 : 0;
151 l
->readlock
= (type
== WRITELOCK
) ? 0 : 1;
153 if(l
->name
!= LOG_LIST
)
154 { cs_log("WARNING lock %s (%s) timed out.", l
->name
, (type
== WRITELOCK
) ? "WRITELOCK" : "READLOCK"); }
158 SAFE_MUTEX_UNLOCK_NOLOG_R(&l
->lock
, n
);
159 #ifdef WITH_MUTEXDEBUG
160 //cs_log_dbg(D_TRACE, "lock %s locked", l->name);
165 void cs_rwunlock_int(const char *n
, CS_MUTEX_LOCK
*l
, int8_t type
)
168 if(!l
|| l
->flag
) { return; }
170 SAFE_MUTEX_LOCK_R(&l
->lock
, n
);
172 if(type
== WRITELOCK
)
177 if(l
->writelock
< 0) { l
->writelock
= 0; }
178 if(l
->readlock
< 0) { l
->readlock
= 0; }
180 // waiting writelocks always have priority. If one is waiting, signal it
182 { SAFE_COND_SIGNAL_R(&l
->writecond
, n
); }
183 // Otherwise signal a waiting readlock (if any)
184 else if(l
->readlock
&& type
!= READLOCK
)
185 { SAFE_COND_BROADCAST_R(&l
->readcond
, n
); }
187 SAFE_MUTEX_UNLOCK_R(&l
->lock
, n
);
189 #ifdef WITH_MUTEXDEBUG
191 if(l
->name
!= LOG_LIST
)
193 const char *typetxt
[] = { "", "write", "read" };
194 cs_log_dbg(D_TRACE
, "%slock %s: released", typetxt
[type
], l
->name
);
200 void cs_rwunlock_int_nolog(const char *n
, CS_MUTEX_LOCK
*l
, int8_t type
)
203 if(!l
|| l
->flag
) { return; }
205 SAFE_MUTEX_LOCK_NOLOG_R(&l
->lock
, n
);
207 if(type
== WRITELOCK
)
212 if(l
->writelock
< 0) { l
->writelock
= 0; }
213 if(l
->readlock
< 0) { l
->readlock
= 0; }
215 // waiting writelocks always have priority. If one is waiting, signal it
217 { SAFE_COND_SIGNAL_R(&l
->writecond
, n
); }
218 // Otherwise signal a waiting readlock (if any)
219 else if(l
->readlock
&& type
!= READLOCK
)
220 { SAFE_COND_BROADCAST_R(&l
->readcond
, n
); }
222 SAFE_MUTEX_UNLOCK_NOLOG_R(&l
->lock
, n
);
224 #ifdef WITH_MUTEXDEBUG
226 if(l
->name
!= LOG_LIST
)
228 const char *typetxt
[] = { "", "write", "read" };
229 cs_log_dbg(D_TRACE
, "%slock %s: released", typetxt
[type
], l
->name
);
235 int8_t cs_try_rwlock_int(const char *n
, CS_MUTEX_LOCK
*l
, int8_t type
)
237 if(!l
|| !l
->name
|| l
->flag
)
242 SAFE_MUTEX_LOCK_R(&l
->lock
, n
);
244 if(type
== WRITELOCK
)
246 if(l
->writelock
|| l
->readlock
)
259 SAFE_MUTEX_UNLOCK_R(&l
->lock
, n
);
261 #ifdef WITH_MUTEXDEBUG
263 if(l
->name
!= LOG_LIST
)
265 const char *typetxt
[] = { "", "write", "read" };
266 cs_log_dbg(D_TRACE
, "try_%slock %s: status=%d", typetxt
[type
], l
->name
, status
);