Esempio n. 1
0
/**********************************************************************
Low-level function for acquiring an exclusive lock. */
UNIV_INLINE
ulint
rw_lock_x_lock_low(
    /*===============*/
    /* out: RW_LOCK_NOT_LOCKED if did
    not succeed, RW_LOCK_EX if success,
    RW_LOCK_WAIT_EX, if got wait reservation */
    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 */
{
    ut_ad(mutex_own(rw_lock_get_mutex(lock)));

    if (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) {

        if (rw_lock_get_reader_count(lock) == 0) {

            rw_lock_set_writer(lock, RW_LOCK_EX);
            lock->writer_thread = os_thread_get_curr_id();
            lock->writer_count++;
            lock->pass = pass;

#ifdef UNIV_SYNC_DEBUG
            rw_lock_add_debug_info(lock, pass, RW_LOCK_EX,
                                   file_name, line);
#endif
            lock->last_x_file_name = file_name;
            lock->last_x_line = (unsigned int) line;

            /* Locking succeeded, we may return */
            return(RW_LOCK_EX);
        } else {
            /* There are readers, we have to wait */
            rw_lock_set_writer(lock, RW_LOCK_WAIT_EX);
            lock->writer_thread = os_thread_get_curr_id();
            lock->pass = pass;
            lock->writer_is_wait_ex = TRUE;

#ifdef UNIV_SYNC_DEBUG
            rw_lock_add_debug_info(lock, pass, RW_LOCK_WAIT_EX,
                                   file_name, line);
#endif

            return(RW_LOCK_WAIT_EX);
        }

    } else if ((rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX)
               && os_thread_eq(lock->writer_thread,
                               os_thread_get_curr_id())) {

        if (rw_lock_get_reader_count(lock) == 0) {

            rw_lock_set_writer(lock, RW_LOCK_EX);
            lock->writer_count++;
            lock->pass = pass;
            lock->writer_is_wait_ex = FALSE;

#ifdef UNIV_SYNC_DEBUG
            rw_lock_remove_debug_info(lock, pass, RW_LOCK_WAIT_EX);
            rw_lock_add_debug_info(lock, pass, RW_LOCK_EX,
                                   file_name, line);
#endif

            lock->last_x_file_name = file_name;
            lock->last_x_line = (unsigned int) line;

            /* Locking succeeded, we may return */
            return(RW_LOCK_EX);
        }

        return(RW_LOCK_WAIT_EX);

    } else if ((rw_lock_get_writer(lock) == RW_LOCK_EX)
               && os_thread_eq(lock->writer_thread,
                               os_thread_get_curr_id())
               && (lock->pass == 0)
               && (pass == 0)) {

        lock->writer_count++;

#ifdef UNIV_SYNC_DEBUG
        rw_lock_add_debug_info(lock, pass, RW_LOCK_EX, file_name,
                               line);
#endif

        lock->last_x_file_name = file_name;
        lock->last_x_line = (unsigned int) line;

        /* Locking succeeded, we may return */
        return(RW_LOCK_EX);
    }

    /* Locking did not succeed */
    return(RW_LOCK_NOT_LOCKED);
}
Esempio n. 2
0
/******************************************************************//**
Function for the next writer to call. Waits for readers to exit.
The caller must have already decremented lock_word by X_LOCK_DECR. */
UNIV_INLINE
void
rw_lock_x_lock_wait(
/*================*/
	rw_lock_t*	lock,	/*!< in: pointer to rw-lock */
#ifdef UNIV_SYNC_DEBUG
	ulint		pass,	/*!< in: pass value; != 0, if the lock will
				be passed to another thread to unlock */
#endif
	const char*	file_name,/*!< in: file name where lock requested */
	ulint		line)	/*!< in: line where requested */
{
	ulint index;
	ulint i = 0;

	ut_ad(lock->lock_word <= 0);

	while (lock->lock_word < 0) {
		if (srv_spin_wait_delay) {
			ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
		}
		if(i < SYNC_SPIN_ROUNDS) {
			i++;
			continue;
		}

		/* If there is still a reader, then go to sleep.*/
		rw_x_spin_round_count += i;
		i = 0;
		sync_array_reserve_cell(sync_primary_wait_array,
					lock,
					RW_LOCK_WAIT_EX,
					file_name, line,
					&index);
		/* Check lock_word to ensure wake-up isn't missed.*/
		if(lock->lock_word < 0) {

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

                        /* Add debug info as it is needed to detect possible
                        deadlock. We must add info for WAIT_EX thread for
                        deadlock detection to work properly. */
#ifdef UNIV_SYNC_DEBUG
			rw_lock_add_debug_info(lock, pass, RW_LOCK_WAIT_EX,
					       file_name, line);
#endif

			sync_array_wait_event(sync_primary_wait_array,
					      index);
#ifdef UNIV_SYNC_DEBUG
			rw_lock_remove_debug_info(lock, pass,
					       RW_LOCK_WAIT_EX);
#endif
                        /* It is possible to wake when lock_word < 0.
                        We must pass the while-loop check to proceed.*/
		} else {
			sync_array_free_cell(sync_primary_wait_array,
					     index);
		}
	}
	rw_x_spin_round_count += i;
}