sync0ipm.ic 3.65 KB
Newer Older
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
/******************************************************
A fast mutex for interprocess synchronization.
mutex_t can be used only within single process,
but ip_mutex_t also between processes.

(c) 1995 Innobase Oy

Created 9/30/1995 Heikki Tuuri
*******************************************************/

/* An extra structure created in the private address space of each process
which creates or opens the ip mutex. */

struct ip_mutex_hdl_struct {
	ip_mutex_t*	ip_mutex;	/* pointer to ip mutex */
	os_event_t	released;	/* event which signals that the mutex
					is released; this is obtained from
					create or open of an ip mutex */
	os_mutex_t	exclude;	/* os mutex obtained when ip mutex is
					created or opened */
};


UNIV_INLINE
ulint
ip_mutex_get_waiters(
volatile ip_mutex_t*	ipm);
UNIV_INLINE
void
ip_mutex_set_waiters(
volatile ip_mutex_t*	ipm,
	ulint		flag);
UNIV_INLINE
mutex_t*
ip_mutex_get_mutex(
	ip_mutex_t*	ipm);


/******************************************************************
Accessor functions for ip mutex. */
UNIV_INLINE
ulint
ip_mutex_get_waiters(
volatile ip_mutex_t*	ipm)
{
	return(ipm->waiters);
}
UNIV_INLINE
void
ip_mutex_set_waiters(
volatile ip_mutex_t*	ipm,
	ulint		flag)
{
	ipm->waiters = flag;
}
UNIV_INLINE
mutex_t*
ip_mutex_get_mutex(
	ip_mutex_t*	ipm)
{
	return(&(ipm->mutex));
}

/******************************************************************
Reserves an ip mutex. */
UNIV_INLINE
ulint
ip_mutex_enter(
/*===========*/
					/* out: 0 if success, 
					SYNC_TIME_EXCEEDED if timeout */
	ip_mutex_hdl_t*	ip_mutex_hdl,	/* in: pointer to ip mutex handle */
	ulint		time)		/* in: maximum time to wait, in
					microseconds, or 
					SYNC_INFINITE_TIME */
{
	mutex_t*	mutex;
	os_event_t	released;
	os_mutex_t	exclude;
	ip_mutex_t*	ip_mutex;
	ulint		loop_count;
	ulint		ret;

	ip_mutex = ip_mutex_hdl->ip_mutex;
	released = ip_mutex_hdl->released;
	exclude = ip_mutex_hdl->exclude;

	mutex = ip_mutex_get_mutex(ip_mutex);

	loop_count = 0;
loop:
	loop_count++;
	ut_ad(loop_count < 15);

95
	if (mutex_enter_nowait(mutex, IB__FILE__, __LINE__) == 0) {
96 97 98 99 100 101 102 103 104 105 106 107
		/* Succeeded! */

		return(0);
	}
	
	ip_mutex_system_call_count++;

	os_event_reset(released);

	/* Order is important here: FIRST reset event, then set waiters */
	ip_mutex_set_waiters(ip_mutex, 1);

108
	if (mutex_enter_nowait(mutex, IB__FILE__, __LINE__) == 0) {
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
		/* Succeeded! */

		return(0);
	}

	if (time == SYNC_INFINITE_TIME) {
		time = OS_SYNC_INFINITE_TIME;
	}

	/* Suspend to wait for release */

	ip_mutex_system_call_count++;

	ret = os_event_wait_time(released, time);

	ip_mutex_system_call_count++;

	os_mutex_enter(exclude);
	ip_mutex_system_call_count++;
	os_mutex_exit(exclude);

	if (ret != 0) {
		ut_a(ret == OS_SYNC_TIME_EXCEEDED);

		return(SYNC_TIME_EXCEEDED);
	}

	goto loop;
}

/******************************************************************
Releases an ip mutex. */
UNIV_INLINE
void
ip_mutex_exit(
/*==========*/
	ip_mutex_hdl_t*	ip_mutex_hdl)	/* in: pointer to ip mutex handle */
{
	mutex_t*	mutex;
	os_event_t	released;
	os_mutex_t	exclude;
	ip_mutex_t*	ip_mutex;

	ip_mutex = ip_mutex_hdl->ip_mutex;
	released = ip_mutex_hdl->released;
	exclude = ip_mutex_hdl->exclude;

	mutex = ip_mutex_get_mutex(ip_mutex);

	mutex_exit(mutex);

	if (ip_mutex_get_waiters(ip_mutex) != 0) {
		
		ip_mutex_set_waiters(ip_mutex, 0);

		/* Order is important here: FIRST reset waiters, 
		then set event */

		ip_mutex_system_call_count++;
		os_mutex_enter(exclude);					

		/* The use of the exclude mutex seems to prevent some
		kind of a convoy problem in the test tsproc.c. We do
		not know why. */

		ip_mutex_system_call_count++;

		os_event_set(released);
	
		ip_mutex_system_call_count++;

		os_mutex_exit(exclude);
	}
}