1 /* $NetBSD: rumpuser_pth.c,v 1.39 2009/11/19 14:44:58 pooka Exp $ */
4 * Copyright (c) 2007 Antti Kantee. All Rights Reserved.
6 * Development of this software was supported by the
7 * Finnish Cultural Foundation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: rumpuser_pth.c,v 1.39 2009/11/19 14:44:58 pooka Exp $");
37 #define _XOPEN_SOURCE 500
39 #define _FILE_OFFSET_BITS 64
51 #include <rump/rumpuser.h>
53 #include "rumpuser_int.h"
55 static pthread_key_t curlwpkey
;
57 #define NOFAIL(a) do {if (!(a)) abort();} while (/*CONSTCOND*/0)
58 #define NOFAIL_ERRNO(a) \
62 printf("panic: rumpuser fatal failure %d (%s)\n", \
63 fail_rv, strerror(fail_rv)); \
66 } while (/*CONSTCOND*/0)
68 #define RUMTX_INCRECURSION(mtx) ((mtx)->recursion++)
69 #define RUMTX_DECRECURSION(mtx) ((mtx)->recursion--)
71 pthread_mutex_t pthmtx
;
76 #define RURW_AMWRITER(rw) (pthread_equal(rw->writer, pthread_self()) \
78 #define RURW_HASREAD(rw) (rw->readers > 0)
80 #define RURW_SETWRITE(rw) \
82 assert(rw->readers == 0); \
83 rw->writer = pthread_self(); \
85 } while (/*CONSTCOND*/0)
86 #define RURW_CLRWRITE(rw) \
88 assert(rw->readers == -1 && RURW_AMWRITER(rw)); \
90 } while (/*CONSTCOND*/0)
91 #define RURW_INCREAD(rw) \
93 pthread_spin_lock(&rw->spin); \
94 assert(rw->readers >= 0); \
96 pthread_spin_unlock(&rw->spin); \
97 } while (/*CONSTCOND*/0)
98 #define RURW_DECREAD(rw) \
100 pthread_spin_lock(&rw->spin); \
101 assert(rw->readers > 0); \
103 pthread_spin_unlock(&rw->spin); \
104 } while (/*CONSTCOND*/0)
107 pthread_rwlock_t pthrw
;
108 pthread_spinlock_t spin
;
114 pthread_cond_t pthcv
;
118 struct rumpuser_mtx rumpuser_aio_mtx
;
119 struct rumpuser_cv rumpuser_aio_cv
;
120 int rumpuser_aio_head
, rumpuser_aio_tail
;
121 struct rumpuser_aio rumpuser_aios
[N_AIOS
];
123 kernel_lockfn rumpuser__klock
;
124 kernel_unlockfn rumpuser__kunlock
;
125 int rumpuser__wantthreads
;
129 rumpuser_biothread(void *arg
)
131 struct rumpuser_aio
*rua
;
132 rump_biodone_fn biodone
= arg
;
136 /* unschedule from CPU. we reschedule before running the interrupt */
137 rumpuser__kunlock(0, &dummy
);
140 NOFAIL_ERRNO(pthread_mutex_lock(&rumpuser_aio_mtx
.pthmtx
));
142 while (rumpuser_aio_head
== rumpuser_aio_tail
) {
143 NOFAIL_ERRNO(pthread_cond_wait(&rumpuser_aio_cv
.pthcv
,
144 &rumpuser_aio_mtx
.pthmtx
));
147 rua
= &rumpuser_aios
[rumpuser_aio_tail
];
148 assert(rua
->rua_bp
!= NULL
);
149 pthread_mutex_unlock(&rumpuser_aio_mtx
.pthmtx
);
151 if (rua
->rua_op
& RUA_OP_READ
) {
153 rv
= pread(rua
->rua_fd
, rua
->rua_data
,
154 rua
->rua_dlen
, rua
->rua_off
);
161 rv
= pwrite(rua
->rua_fd
, rua
->rua_data
,
162 rua
->rua_dlen
, rua
->rua_off
);
166 } else if (rua
->rua_op
& RUA_OP_SYNC
) {
168 fsync_range(rua
->rua_fd
, FDATASYNC
,
169 rua
->rua_off
, rua
->rua_dlen
);
176 biodone(rua
->rua_bp
, (size_t)rv
, error
);
177 rumpuser__kunlock(0, &dummy
);
181 NOFAIL_ERRNO(pthread_mutex_lock(&rumpuser_aio_mtx
.pthmtx
));
182 rumpuser_aio_tail
= (rumpuser_aio_tail
+1) % N_AIOS
;
183 pthread_cond_signal(&rumpuser_aio_cv
.pthcv
);
187 fprintf(stderr
, "error: rumpuser_biothread reached unreachable\n");
192 rumpuser_thrinit(kernel_lockfn lockfn
, kernel_unlockfn unlockfn
, int threads
)
195 pthread_mutex_init(&rumpuser_aio_mtx
.pthmtx
, NULL
);
196 pthread_cond_init(&rumpuser_aio_cv
.pthcv
, NULL
);
198 pthread_key_create(&curlwpkey
, NULL
);
200 rumpuser__klock
= lockfn
;
201 rumpuser__kunlock
= unlockfn
;
202 rumpuser__wantthreads
= threads
;
207 rumpuser__thrdestroy(void)
210 pthread_key_delete(curlwpkey
);
215 rumpuser_thread_create(void *(*f
)(void *), void *arg
, const char *thrname
)
220 rv
= pthread_create(&ptid
, NULL
, f
, arg
);
222 if (rv
== 0 && thrname
)
223 pthread_setname_np(ptid
, thrname
, NULL
);
230 rumpuser_thread_exit(void)
237 rumpuser_mutex_init(struct rumpuser_mtx
**mtx
)
239 pthread_mutexattr_t att
;
241 NOFAIL(*mtx
= malloc(sizeof(struct rumpuser_mtx
)));
243 pthread_mutexattr_init(&att
);
244 pthread_mutexattr_settype(&att
, PTHREAD_MUTEX_ERRORCHECK
);
245 NOFAIL_ERRNO(pthread_mutex_init(&((*mtx
)->pthmtx
), &att
));
246 pthread_mutexattr_destroy(&att
);
248 (*mtx
)->owner
= NULL
;
249 (*mtx
)->recursion
= 0;
253 rumpuser_mutex_recursive_init(struct rumpuser_mtx
**mtx
)
255 pthread_mutexattr_t mattr
;
257 pthread_mutexattr_init(&mattr
);
258 pthread_mutexattr_settype(&mattr
, PTHREAD_MUTEX_RECURSIVE
);
260 NOFAIL(*mtx
= malloc(sizeof(struct rumpuser_mtx
)));
261 NOFAIL_ERRNO(pthread_mutex_init(&((*mtx
)->pthmtx
), &mattr
));
262 (*mtx
)->owner
= NULL
;
263 (*mtx
)->recursion
= 0;
265 pthread_mutexattr_destroy(&mattr
);
269 mtxenter(struct rumpuser_mtx
*mtx
)
272 if (mtx
->recursion
++ == 0) {
273 assert(mtx
->owner
== NULL
);
274 mtx
->owner
= pthread_self();
276 assert(pthread_equal(mtx
->owner
, pthread_self()));
281 mtxexit(struct rumpuser_mtx
*mtx
)
284 assert(mtx
->owner
!= NULL
);
285 if (--mtx
->recursion
== 0)
290 rumpuser_mutex_enter(struct rumpuser_mtx
*mtx
)
293 if (pthread_mutex_trylock(&mtx
->pthmtx
) != 0)
294 KLOCK_WRAP(NOFAIL_ERRNO(pthread_mutex_lock(&mtx
->pthmtx
)));
299 rumpuser_mutex_enter_nowrap(struct rumpuser_mtx
*mtx
)
302 NOFAIL_ERRNO(pthread_mutex_lock(&mtx
->pthmtx
));
307 rumpuser_mutex_tryenter(struct rumpuser_mtx
*mtx
)
311 rv
= pthread_mutex_trylock(&mtx
->pthmtx
);
320 rumpuser_mutex_exit(struct rumpuser_mtx
*mtx
)
324 NOFAIL_ERRNO(pthread_mutex_unlock(&mtx
->pthmtx
));
328 rumpuser_mutex_destroy(struct rumpuser_mtx
*mtx
)
331 NOFAIL_ERRNO(pthread_mutex_destroy(&mtx
->pthmtx
));
336 rumpuser_mutex_held(struct rumpuser_mtx
*mtx
)
339 return mtx
->recursion
&& pthread_equal(mtx
->owner
, pthread_self());
343 rumpuser_rw_init(struct rumpuser_rw
**rw
)
346 NOFAIL(*rw
= malloc(sizeof(struct rumpuser_rw
)));
347 NOFAIL_ERRNO(pthread_rwlock_init(&((*rw
)->pthrw
), NULL
));
348 NOFAIL_ERRNO(pthread_spin_init(&((*rw
)->spin
), PTHREAD_PROCESS_SHARED
));
350 (*rw
)->writer
= NULL
;
354 rumpuser_rw_enter(struct rumpuser_rw
*rw
, int iswrite
)
358 if (pthread_rwlock_trywrlock(&rw
->pthrw
) != 0)
359 KLOCK_WRAP(NOFAIL_ERRNO(
360 pthread_rwlock_wrlock(&rw
->pthrw
)));
363 if (pthread_rwlock_tryrdlock(&rw
->pthrw
) != 0)
364 KLOCK_WRAP(NOFAIL_ERRNO(
365 pthread_rwlock_rdlock(&rw
->pthrw
)));
371 rumpuser_rw_tryenter(struct rumpuser_rw
*rw
, int iswrite
)
376 rv
= pthread_rwlock_trywrlock(&rw
->pthrw
);
380 rv
= pthread_rwlock_tryrdlock(&rw
->pthrw
);
389 rumpuser_rw_exit(struct rumpuser_rw
*rw
)
392 if (RURW_HASREAD(rw
))
396 NOFAIL_ERRNO(pthread_rwlock_unlock(&rw
->pthrw
));
400 rumpuser_rw_destroy(struct rumpuser_rw
*rw
)
403 NOFAIL_ERRNO(pthread_rwlock_destroy(&rw
->pthrw
));
404 NOFAIL_ERRNO(pthread_spin_destroy(&rw
->spin
));
409 rumpuser_rw_held(struct rumpuser_rw
*rw
)
412 return rw
->readers
!= 0;
416 rumpuser_rw_rdheld(struct rumpuser_rw
*rw
)
419 return RURW_HASREAD(rw
);
423 rumpuser_rw_wrheld(struct rumpuser_rw
*rw
)
426 return RURW_AMWRITER(rw
);
430 rumpuser_cv_init(struct rumpuser_cv
**cv
)
433 NOFAIL(*cv
= malloc(sizeof(struct rumpuser_cv
)));
434 NOFAIL_ERRNO(pthread_cond_init(&((*cv
)->pthcv
), NULL
));
439 rumpuser_cv_destroy(struct rumpuser_cv
*cv
)
442 NOFAIL_ERRNO(pthread_cond_destroy(&cv
->pthcv
));
447 rumpuser_cv_wait(struct rumpuser_cv
*cv
, struct rumpuser_mtx
*mtx
)
451 assert(mtx
->recursion
== 1);
453 KLOCK_WRAP(NOFAIL_ERRNO(pthread_cond_wait(&cv
->pthcv
, &mtx
->pthmtx
)));
459 rumpuser_cv_wait_nowrap(struct rumpuser_cv
*cv
, struct rumpuser_mtx
*mtx
)
463 assert(mtx
->recursion
== 1);
465 NOFAIL_ERRNO(pthread_cond_wait(&cv
->pthcv
, &mtx
->pthmtx
));
471 rumpuser_cv_timedwait(struct rumpuser_cv
*cv
, struct rumpuser_mtx
*mtx
,
472 int64_t sec
, int64_t nsec
)
478 ts
.tv_sec
= sec
; ts
.tv_nsec
= nsec
;
482 KLOCK_WRAP(rv
= pthread_cond_timedwait(&cv
->pthcv
, &mtx
->pthmtx
, &ts
));
485 if (rv
!= 0 && rv
!= ETIMEDOUT
)
488 return rv
== ETIMEDOUT
;
492 rumpuser_cv_signal(struct rumpuser_cv
*cv
)
495 NOFAIL_ERRNO(pthread_cond_signal(&cv
->pthcv
));
499 rumpuser_cv_broadcast(struct rumpuser_cv
*cv
)
502 NOFAIL_ERRNO(pthread_cond_broadcast(&cv
->pthcv
));
506 rumpuser_cv_has_waiters(struct rumpuser_cv
*cv
)
517 rumpuser_set_curlwp(struct lwp
*l
)
520 assert(pthread_getspecific(curlwpkey
) == NULL
|| l
== NULL
);
521 pthread_setspecific(curlwpkey
, l
);
525 rumpuser_get_curlwp(void)
528 return pthread_getspecific(curlwpkey
);