Пример #1
0
ibool
rw_lock_own(
    /*========*/
    /* out: TRUE if locked */
    rw_lock_t*	lock,		/* in: rw-lock */
    ulint		lock_type)	/* in: lock type: RW_LOCK_SHARED,
					RW_LOCK_EX */
{
    rw_lock_debug_t*	info;

    ut_ad(lock);
    ut_ad(rw_lock_validate(lock));

    mutex_enter(&(lock->mutex));

    info = UT_LIST_GET_FIRST(lock->debug_list);

    while (info != NULL) {

        if (os_thread_eq(info->thread_id, os_thread_get_curr_id())
                && (info->pass == 0)
                && (info->lock_type == lock_type)) {

            mutex_exit(&(lock->mutex));
            /* Found! */

            return(TRUE);
        }

        info = UT_LIST_GET_NEXT(list, info);
    }
    mutex_exit(&(lock->mutex));

    return(FALSE);
}
Пример #2
0
ibool
rw_lock_is_locked(
    /*==============*/
    /* out: TRUE if locked */
    rw_lock_t*	lock,		/* in: rw-lock */
    ulint		lock_type)	/* in: lock type: RW_LOCK_SHARED,
					RW_LOCK_EX */
{
    ibool	ret	= FALSE;

    ut_ad(lock);
    ut_ad(rw_lock_validate(lock));

    mutex_enter(&(lock->mutex));

    if (lock_type == RW_LOCK_SHARED) {
        if (lock->reader_count > 0) {
            ret = TRUE;
        }
    } else if (lock_type == RW_LOCK_EX) {
        if (lock->writer == RW_LOCK_EX) {
            ret = TRUE;
        }
    } else {
        ut_error;
    }

    mutex_exit(&(lock->mutex));

    return(ret);
}
Пример #3
0
/******************************************************************//**
Checks if somebody has locked the rw-lock in the specified mode.
@return	TRUE if locked */
UNIV_INTERN
ibool
rw_lock_is_locked(
/*==============*/
	rw_lock_t*	lock,		/*!< in: rw-lock */
	ulint		lock_type)	/*!< in: lock type: RW_LOCK_SHARED,
					RW_LOCK_EX */
{
	ibool	ret	= FALSE;

	ut_ad(lock);
	ut_ad(rw_lock_validate(lock));

	if (lock_type == RW_LOCK_SHARED) {
		if (rw_lock_get_reader_count(lock) > 0) {
			ret = TRUE;
		}
	} else if (lock_type == RW_LOCK_EX) {
		if (rw_lock_get_writer(lock) == RW_LOCK_EX) {
			ret = TRUE;
		}
	} else {
		ut_error;
	}

	return(ret);
}
Пример #4
0
void
rw_lock_free(
    /*=========*/
    rw_lock_t*	lock)	/* in: rw-lock */
{
    ut_ad(rw_lock_validate(lock));
    ut_a(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED);
    ut_a(rw_lock_get_waiters(lock) == 0);
    ut_a(rw_lock_get_reader_count(lock) == 0);

    lock->magic_n = 0;

    mutex_free(rw_lock_get_mutex(lock));

    mutex_enter(&rw_lock_list_mutex);
    os_event_free(lock->event);

#ifdef __WIN__
    os_event_free(lock->wait_ex_event);
#endif

    if (UT_LIST_GET_PREV(list, lock)) {
        ut_a(UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N);
    }
    if (UT_LIST_GET_NEXT(list, lock)) {
        ut_a(UT_LIST_GET_NEXT(list, lock)->magic_n == RW_LOCK_MAGIC_N);
    }

    UT_LIST_REMOVE(list, rw_lock_list, lock);

    mutex_exit(&rw_lock_list_mutex);
}
Пример #5
0
/******************************************************************//**
Calling this function is obligatory only if the memory buffer containing
the rw-lock is freed. Removes an rw-lock object from the global list. The
rw-lock is checked to be in the non-locked state. */
UNIV_INTERN
void
rw_lock_free_func(
/*==============*/
	rw_lock_t*	lock)	/*!< in: rw-lock */
{
	ut_ad(rw_lock_validate(lock));
	ut_a(lock->lock_word == X_LOCK_DECR);

#ifndef INNODB_RW_LOCKS_USE_ATOMICS
	mutex_free(rw_lock_get_mutex(lock));
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */

	mutex_enter(&rw_lock_list_mutex);
	os_event_free(lock->event);

	os_event_free(lock->wait_ex_event);

	ut_ad(UT_LIST_GET_PREV(list, lock) == NULL
	      || UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N);
	ut_ad(UT_LIST_GET_NEXT(list, lock) == NULL
	      || UT_LIST_GET_NEXT(list, lock)->magic_n == RW_LOCK_MAGIC_N);

	UT_LIST_REMOVE(list, rw_lock_list, lock);

	mutex_exit(&rw_lock_list_mutex);

	ut_d(lock->magic_n = 0);
}
Пример #6
0
void
rw_lock_free(
    /*=========*/
    rw_lock_t*	lock)	/* in: rw-lock */
{
    ut_ad(rw_lock_validate(lock));
    ut_a(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED);
    ut_a(rw_lock_get_waiters(lock) == 0);
    ut_a(rw_lock_get_reader_count(lock) == 0);

    lock->magic_n = 0;

    mutex_free(rw_lock_get_mutex(lock));

    mutex_enter(&rw_lock_list_mutex);

    UT_LIST_REMOVE(list, rw_lock_list, lock);

    mutex_exit(&rw_lock_list_mutex);
}
Пример #7
0
ibool
rw_lock_own(
    /*========*/
    /* out: TRUE if locked */
    rw_lock_t*	lock,		/* in: rw-lock */
    ulint		lock_type)	/* in: lock type */
{
    rw_lock_debug_t*	info;

    ut_ad(lock);
    ut_ad(rw_lock_validate(lock));

#ifndef UNIV_SYNC_DEBUG
    ut_error;
#endif
    mutex_enter(&(lock->mutex));

    info = UT_LIST_GET_FIRST(lock->debug_list);

    while (info != NULL) {

        if ((info->thread_id == os_thread_get_curr_id())
                && (info->pass == 0)
                && (info->lock_type == lock_type)) {

            mutex_exit(&(lock->mutex));
            /* Found! */

            return(TRUE);
        }

        info = UT_LIST_GET_NEXT(list, info);
    }
    mutex_exit(&(lock->mutex));

    return(FALSE);
}
Пример #8
0
void
rw_lock_x_lock_func(
    /*================*/
    rw_lock_t*	lock,	/* in: pointer to rw-lock */
    ulint		pass,	/* in: pass value; != 0, if the lock will
				be passed to another thread to unlock */
    const char*	file_name,/* in: file name where lock requested */
    ulint		line)	/* in: line where requested */
{
    ulint	index;	/* index of the reserved wait cell */
    ulint	state;	/* lock state acquired */
    ulint	i;	/* spin round count */

    ut_ad(rw_lock_validate(lock));

lock_loop:
    /* Acquire the mutex protecting the rw-lock fields */
    mutex_enter_fast(&(lock->mutex));

    state = rw_lock_x_lock_low(lock, pass, file_name, line);

    mutex_exit(&(lock->mutex));

    if (state == RW_LOCK_EX) {

        return;	/* Locking succeeded */

    } else if (state == RW_LOCK_NOT_LOCKED) {

        /* Spin waiting for the writer field to become free */
        i = 0;

        while (rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED
                && i < SYNC_SPIN_ROUNDS) {
            if (srv_spin_wait_delay) {
                ut_delay(ut_rnd_interval(0,
                                         srv_spin_wait_delay));
            }

            i++;
        }
        if (i == SYNC_SPIN_ROUNDS) {
            os_thread_yield();
        }
    } else if (state == RW_LOCK_WAIT_EX) {

        /* Spin waiting for the reader count field to become zero */
        i = 0;

        while (rw_lock_get_reader_count(lock) != 0
                && i < SYNC_SPIN_ROUNDS) {
            if (srv_spin_wait_delay) {
                ut_delay(ut_rnd_interval(0,
                                         srv_spin_wait_delay));
            }

            i++;
        }
        if (i == SYNC_SPIN_ROUNDS) {
            os_thread_yield();
        }
    } else {
        i = 0; /* Eliminate a compiler warning */
        ut_error;
    }

    if (srv_print_latch_waits) {
        fprintf(stderr,
                "Thread %lu spin wait rw-x-lock at %p"
                " cfile %s cline %lu rnds %lu\n",
                os_thread_pf(os_thread_get_curr_id()), (void*) lock,
                lock->cfile_name, (ulong) lock->cline, (ulong) i);
    }

    rw_x_spin_wait_count++;

    /* We try once again to obtain the lock. Acquire the mutex protecting
    the rw-lock fields */

    mutex_enter(rw_lock_get_mutex(lock));

    state = rw_lock_x_lock_low(lock, pass, file_name, line);

    if (state == RW_LOCK_EX) {
        mutex_exit(rw_lock_get_mutex(lock));

        return;	/* Locking succeeded */
    }

    rw_x_system_call_count++;

    sync_array_reserve_cell(sync_primary_wait_array,
                            lock,
#ifdef __WIN__
                            /* On windows RW_LOCK_WAIT_EX signifies
                            that this thread should wait on the
                            special wait_ex_event. */
                            (state == RW_LOCK_WAIT_EX)
                            ? RW_LOCK_WAIT_EX :
#endif
                            RW_LOCK_EX,
                            file_name, line,
                            &index);

    rw_lock_set_waiters(lock, 1);

    mutex_exit(rw_lock_get_mutex(lock));

    if (srv_print_latch_waits) {
        fprintf(stderr,
                "Thread %lu OS wait for rw-x-lock at %p"
                " cfile %s cline %lu\n",
                os_thread_pf(os_thread_get_curr_id()), (void*) lock,
                lock->cfile_name, (ulong) lock->cline);
    }

    rw_x_system_call_count++;
    rw_x_os_wait_count++;

    sync_array_wait_event(sync_primary_wait_array, index);

    goto lock_loop;
}
Пример #9
0
void
rw_lock_s_lock_spin(
    /*================*/
    rw_lock_t*	lock,	/* in: pointer to rw-lock */
    ulint		pass,	/* in: pass value; != 0, if the lock
				will be passed to another thread to unlock */
    const char*	file_name, /* in: file name where lock requested */
    ulint		line)	/* in: line where requested */
{
    ulint	 index;	/* index of the reserved wait cell */
    ulint	 i;	/* spin round count */

    ut_ad(rw_lock_validate(lock));

lock_loop:
    rw_s_spin_wait_count++;

    /* Spin waiting for the writer field to become free */
    i = 0;

    while (rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED
            && i < SYNC_SPIN_ROUNDS) {
        if (srv_spin_wait_delay) {
            ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
        }

        i++;
    }

    if (i == SYNC_SPIN_ROUNDS) {
        os_thread_yield();
    }

    if (srv_print_latch_waits) {
        fprintf(stderr,
                "Thread %lu spin wait rw-s-lock at %p"
                " cfile %s cline %lu rnds %lu\n",
                (ulong) os_thread_pf(os_thread_get_curr_id()),
                (void*) lock,
                lock->cfile_name, (ulong) lock->cline, (ulong) i);
    }

    mutex_enter(rw_lock_get_mutex(lock));

    /* We try once again to obtain the lock */

    if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
        mutex_exit(rw_lock_get_mutex(lock));

        return; /* Success */
    } else {
        /* If we get here, locking did not succeed, we may
        suspend the thread to wait in the wait array */

        rw_s_system_call_count++;

        sync_array_reserve_cell(sync_primary_wait_array,
                                lock, RW_LOCK_SHARED,
                                file_name, line,
                                &index);

        rw_lock_set_waiters(lock, 1);

        mutex_exit(rw_lock_get_mutex(lock));

        if (srv_print_latch_waits) {
            fprintf(stderr,
                    "Thread %lu OS wait rw-s-lock at %p"
                    " cfile %s cline %lu\n",
                    os_thread_pf(os_thread_get_curr_id()),
                    (void*) lock, lock->cfile_name,
                    (ulong) lock->cline);
        }

        rw_s_system_call_count++;
        rw_s_os_wait_count++;

        sync_array_wait_event(sync_primary_wait_array, index);

        goto lock_loop;
    }
}
Пример #10
0
/******************************************************************//**
NOTE! Use the corresponding macro, not directly this function! Lock an
rw-lock in exclusive mode for the current thread. If the rw-lock is locked
in shared or exclusive mode, or there is an exclusive lock request waiting,
the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting
for the lock before suspending the thread. If the same thread has an x-lock
on the rw-lock, locking succeed, with the following exception: if pass != 0,
only a single x-lock may be taken on the lock. NOTE: If the same thread has
an s-lock, locking does not succeed! */
UNIV_INTERN
void
rw_lock_x_lock_func(
/*================*/
	rw_lock_t*	lock,	/*!< in: pointer to rw-lock */
	ulint		pass,	/*!< in: pass value; != 0, if the lock will
				be passed to another thread to unlock */
	const char*	file_name,/*!< in: file name where lock requested */
	ulint		line)	/*!< in: line where requested */
{
	ulint	index;	/*!< index of the reserved wait cell */
	ulint	i;	/*!< spin round count */
	ibool	spinning = FALSE;

	ut_ad(rw_lock_validate(lock));
#ifdef UNIV_SYNC_DEBUG
	ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED));
#endif /* UNIV_SYNC_DEBUG */

	i = 0;

lock_loop:

	if (rw_lock_x_lock_low(lock, pass, file_name, line)) {
		rw_x_spin_round_count += i;

		return;	/* Locking succeeded */

	} else {

                if (!spinning) {
                        spinning = TRUE;
                        rw_x_spin_wait_count++;
		}

		/* Spin waiting for the lock_word to become free */
		while (i < SYNC_SPIN_ROUNDS
		       && lock->lock_word <= 0) {
			if (srv_spin_wait_delay) {
				ut_delay(ut_rnd_interval(0,
							 srv_spin_wait_delay));
			}

			i++;
		}
		if (i == SYNC_SPIN_ROUNDS) {
			os_thread_yield();
		} else {
			goto lock_loop;
		}
	}

	rw_x_spin_round_count += i;

	if (srv_print_latch_waits) {
		fprintf(stderr,
			"Thread %lu spin wait rw-x-lock at %p"
			" cfile %s cline %lu rnds %lu\n",
			os_thread_pf(os_thread_get_curr_id()), (void*) lock,
			innobase_basename(lock->cfile_name),
			(ulong) lock->cline, (ulong) i);
	}

	sync_array_reserve_cell(sync_primary_wait_array,
				lock,
				RW_LOCK_EX,
				file_name, line,
				&index);

	/* Waiters must be set before checking lock_word, to ensure signal
	is sent. This could lead to a few unnecessary wake-up signals. */
	rw_lock_set_waiter_flag(lock);

	if (rw_lock_x_lock_low(lock, pass, file_name, line)) {
		sync_array_free_cell(sync_primary_wait_array, index);
		return; /* Locking succeeded */
	}

	if (srv_print_latch_waits) {
		fprintf(stderr,
			"Thread %lu OS wait for rw-x-lock at %p"
			" cfile %s cline %lu\n",
			os_thread_pf(os_thread_get_curr_id()), (void*) lock,
			innobase_basename(lock->cfile_name),
			(ulong) lock->cline);
	}

	/* these stats may not be accurate */
	lock->count_os_wait++;
	rw_x_os_wait_count++;

	sync_array_wait_event(sync_primary_wait_array, index);

	i = 0;
	goto lock_loop;
}
Пример #11
0
/******************************************************************//**
Lock an rw-lock in shared mode for the current thread. If the rw-lock is
locked in exclusive mode, or there is an exclusive lock request waiting,
the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting
for the lock, before suspending the thread. */
UNIV_INTERN
void
rw_lock_s_lock_spin(
/*================*/
	rw_lock_t*	lock,	/*!< in: pointer to rw-lock */
	ulint		pass,	/*!< in: pass value; != 0, if the lock
				will be passed to another thread to unlock */
	const char*	file_name, /*!< in: file name where lock requested */
	ulint		line)	/*!< in: line where requested */
{
	ulint	 index;	/* index of the reserved wait cell */
	ulint	 i = 0;	/* spin round count */

	ut_ad(rw_lock_validate(lock));

	rw_s_spin_wait_count++;	/*!< Count calls to this function */
lock_loop:

	/* Spin waiting for the writer field to become free */
	while (i < SYNC_SPIN_ROUNDS && lock->lock_word <= 0) {
		if (srv_spin_wait_delay) {
			ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
		}

		i++;
	}

	if (i == SYNC_SPIN_ROUNDS) {
		os_thread_yield();
	}

	if (srv_print_latch_waits) {
		fprintf(stderr,
			"Thread %lu spin wait rw-s-lock at %p"
			" cfile %s cline %lu rnds %lu\n",
			(ulong) os_thread_pf(os_thread_get_curr_id()),
			(void*) lock,
			innobase_basename(lock->cfile_name),
			(ulong) lock->cline, (ulong) i);
	}

	/* We try once again to obtain the lock */
	if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
		rw_s_spin_round_count += i;

		return; /* Success */
	} else {

		if (i < SYNC_SPIN_ROUNDS) {
			goto lock_loop;
		}

		rw_s_spin_round_count += i;

		sync_array_reserve_cell(sync_primary_wait_array,
					lock, RW_LOCK_SHARED,
					file_name, line,
					&index);

		/* Set waiters before checking lock_word to ensure wake-up
                signal is sent. This may lead to some unnecessary signals. */
		rw_lock_set_waiter_flag(lock);

		if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
			sync_array_free_cell(sync_primary_wait_array, index);
			return; /* Success */
		}

		if (srv_print_latch_waits) {
			fprintf(stderr,
				"Thread %lu OS wait rw-s-lock at %p"
				" cfile %s cline %lu\n",
				os_thread_pf(os_thread_get_curr_id()),
				(void*) lock,
				innobase_basename(lock->cfile_name),
				(ulong) lock->cline);
		}

		/* these stats may not be accurate */
		lock->count_os_wait++;
		rw_s_os_wait_count++;

		sync_array_wait_event(sync_primary_wait_array, index);

		i = 0;
		goto lock_loop;
	}
}