summaryrefslogtreecommitdiff
path: root/src/tet3/apithr/api_lock.c
blob: 81bf2f64ab6eb2429c9e83d6493a4f69a5037858 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
 *	SCCS: @(#)api_lock.c	1.9 (98/08/28)
 *
 *	UniSoft Ltd., London, England
 *
 * (C) Copyright 1996 X/Open Company Limited
 *
 * All rights reserved.  No part of this source code may be reproduced,
 * stored in a retrieval system, or transmitted, in any form or by any
 * means, electronic, mechanical, photocopying, recording or otherwise,
 * except as stated in the end-user licence agreement, without the prior
 * permission of the copyright owners.
 * A copy of the end-user licence agreement is contained in the file
 * Licence which accompanies this distribution.
 * 
 * X/Open and the 'X' symbol are trademarks of X/Open Company Limited in
 * the UK and other countries.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif


/************************************************************************

SCCS:   	@(#)api_lock.c	1.9 98/08/28 TETware release 3.3
NAME:		API lock/unlock function
PRODUCT:	TETware
AUTHOR:		Geoff Clare, UniSoft Ltd.
DATE CREATED:	July 1996
SYNOPSIS:

	void	tet_api_lock(int getlock, const char *file, int line);

DESCRIPTION:

	Tet_api_lock() is used to implement a top-level API mutex
	that can be used in a nested fashion via the macros API_LOCK
	and API_UNLOCK.  When an API function calls another the
	underlying mutex is not unlocked at the end of the called
	function, only at the end of the calling function.

	On UNIX systems all blockable signals are blocked while the mutex
	is held, so that the thread cannot call TET_THR_EXIT() from a signal
	handler (leaving the mutex locked).  Any API function which needs
	to catch a signal must be sure to unblock it.

MODIFICATIONS:
	Geoff Clare, UniSoft Ltd., Oct 1996
	Use TET_THR_EQUAL() to compare thread IDs.

	Geoff Clare, UniSoft Ltd., July 1997
	Changes to support NT threads.

	Andrew Dingwall, UniSoft Ltd., February 1998
	Use TETware-specific macros to access threads functions and
	data items.

************************************************************************/

#include <string.h>
#include <signal.h>
#include "dtmac.h"
#include "error.h"
#include "dtthr.h"
#include "sigsafe.h"

#ifndef NOTRACE
#include "ltoa.h"
#endif

extern tet_mutex_t tet_top_mtx;

void
tet_api_lock(int getlock, const char *file, int line)
{
	sigset_t tmpset;
	static sigset_t oset;
	static int nestlevel;
	static tet_thread_t ownertid; /* only valid when nestlevel > 0 */

	if (getlock)
	{
		TRACE3(tet_Ttcm, 5, "API_LOCK requested from %s, %s",
			file, tet_i2a(line));

		/* grab the top-level mutex, if not nested */
		if (nestlevel == 0 || !TET_THR_EQUAL(ownertid, TET_THR_SELF()))
		{
			if (TET_THR_SIGSETMASK(SIG_BLOCK, &tet_blockable_sigs,
				&tmpset) != 0)
			{
				fatal(0, "TET_THR_SIGSETMASK() failed in tet_api_lock()", (char *)0);
			}
			TET_MUTEX_LOCK(&tet_top_mtx);
			ownertid = TET_THR_SELF();

			/* now it's safe to store the old signal set */
			(void) memcpy((void *)&oset, (void *)&tmpset, sizeof oset);
		}
		nestlevel++;

		TRACE4(tet_Ttcm, 5, "API_LOCK (%s, %s) nestlevel %s",
			file, tet_i2a(line), tet_i2a(nestlevel));
	}
	else
	{
		/* release the top-level mutex, if not nested */
		ASSERT(nestlevel > 0);
		ASSERT(TET_THR_EQUAL(ownertid, TET_THR_SELF()));
		TRACE4(tet_Ttcm, 5, "API_UNLOCK (%s, %s) nestlevel %s",
			file, tet_i2a(line), tet_i2a(nestlevel));
		nestlevel--;
		if (nestlevel == 0)
		{
			/* copy signal set to safe storage before unlocking */
			(void) memcpy((void *)&tmpset, (void *)&oset, sizeof oset);

			TET_MUTEX_UNLOCK(&tet_top_mtx);

			(void) TET_THR_SIGSETMASK(SIG_SETMASK, &tmpset, (sigset_t *)0);
		}
	}
}