1/*	$NetBSD: flockfile.c,v 1.10 2010/12/08 02:07:03 joerg Exp $	*/
2
3/*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Nathan J. Williams.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33#if defined(LIBC_SCCS) && !defined(lint)
34__RCSID("$NetBSD: flockfile.c,v 1.10 2010/12/08 02:07:03 joerg Exp $");
35#endif /* LIBC_SCCS and not lint */
36
37#include "namespace.h"
38
39#include <assert.h>
40#include <errno.h>
41#include <stdio.h>
42#include <string.h>
43#include "reentrant.h"
44#include "local.h"
45
46#ifdef __weak_alias
47__weak_alias(flockfile,_flockfile)
48__weak_alias(ftrylockfile,_ftrylockfile)
49__weak_alias(funlockfile,_funlockfile)
50#endif
51
52#ifdef _REENTRANT
53/*
54 * XXX This code makes the assumption that a thr_t (pthread_t) is a
55 * XXX pointer.
56 */
57
58void
59flockfile(FILE *fp)
60{
61
62	__flockfile_internal(fp, 0);
63}
64
65int
66ftrylockfile(FILE *fp)
67{
68	int retval;
69
70	if (__isthreaded == 0)
71		return 0;
72
73	retval = 0;
74	mutex_lock(&_LOCK(fp));
75
76	if (_LOCKOWNER(fp) == thr_self()) {
77		_LOCKCOUNT(fp)++;
78	} else if (_LOCKOWNER(fp) == NULL) {
79		_LOCKOWNER(fp) = thr_self();
80		_LOCKCOUNT(fp) = 1;
81	} else
82		retval = -1;
83
84	mutex_unlock(&_LOCK(fp));
85
86	return retval;
87}
88
89void
90funlockfile(FILE *fp)
91{
92
93	__funlockfile_internal(fp, 0);
94}
95
96void
97__flockfile_internal(FILE *fp, int internal)
98{
99
100	if (__isthreaded == 0)
101		return;
102
103	mutex_lock(&_LOCK(fp));
104
105	if (_LOCKOWNER(fp) == thr_self()) {
106		_LOCKCOUNT(fp)++;
107		if (internal)
108			_LOCKINTERNAL(fp)++;
109	} else {
110		/* danger! cond_wait() is a cancellation point. */
111		int oldstate;
112		thr_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
113		while (_LOCKOWNER(fp) != NULL)
114			cond_wait(&_LOCKCOND(fp), &_LOCK(fp));
115		thr_setcancelstate(oldstate, NULL);
116		_LOCKOWNER(fp) = thr_self();
117		_LOCKCOUNT(fp) = 1;
118		if (internal)
119			_LOCKINTERNAL(fp) = 1;
120	}
121
122	if (_LOCKINTERNAL(fp) == 1)
123		/* stash cancellation state and disable */
124		thr_setcancelstate(PTHREAD_CANCEL_DISABLE,
125		    &_LOCKCANCELSTATE(fp));
126
127	mutex_unlock(&_LOCK(fp));
128}
129
130void
131__funlockfile_internal(FILE *fp, int internal)
132{
133
134	if (__isthreaded == 0)
135		return;
136
137	mutex_lock(&_LOCK(fp));
138
139	if (internal) {
140		_LOCKINTERNAL(fp)--;
141		if (_LOCKINTERNAL(fp) == 0)
142			thr_setcancelstate(_LOCKCANCELSTATE(fp), NULL);
143	}
144
145	_LOCKCOUNT(fp)--;
146	if (_LOCKCOUNT(fp) == 0) {
147		_LOCKOWNER(fp) = NULL;
148		cond_signal(&_LOCKCOND(fp));
149	}
150
151	mutex_unlock(&_LOCK(fp));
152}
153
154#else /* _REENTRANT */
155
156void
157flockfile(FILE *fp)
158{
159	/* LINTED deliberate lack of effect */
160	(void)fp;
161
162	return;
163}
164
165int
166ftrylockfile(FILE *fp)
167{
168	/* LINTED deliberate lack of effect */
169	(void)fp;
170
171	return 0;
172}
173
174void
175funlockfile(FILE *fp)
176{
177	/* LINTED deliberate lack of effect */
178	(void)fp;
179
180	return;
181}
182
183#endif /* _REENTRANT */
184