void do_setup_dpll(const struct dpll_regs *dpll_regs, const struct dpll_params *params) { u32 temp; if (!params) return; temp = readl(dpll_regs->cm_clksel_dpll); bypass_dpll(dpll_regs); /* Set M & N */ temp &= ~CM_CLKSEL_DPLL_M_MASK; temp |= (params->m << CM_CLKSEL_DPLL_M_SHIFT) & CM_CLKSEL_DPLL_M_MASK; temp &= ~CM_CLKSEL_DPLL_N_MASK; temp |= (params->n << CM_CLKSEL_DPLL_N_SHIFT) & CM_CLKSEL_DPLL_N_MASK; writel(temp, dpll_regs->cm_clksel_dpll); setup_post_dividers(dpll_regs, params); /* Wait till the DPLL locks */ do_lock_dpll(dpll_regs); wait_for_lock(dpll_regs); }
static void parse_args( int argc, char *argv[] ) { int ret, optc; static struct option long_options[] = { {"debug", 2, NULL, 'd'}, {"foreground", 0, NULL, 'f'}, {"help", 0, NULL, 'h'}, {"kill", 2, NULL, 'k'}, {"persistent", 2, NULL, 'p'}, {"version", 0, NULL, 'v'}, {"wait", 0, NULL, 'w'}, { NULL, 0, NULL, 0} }; server_argv0 = argv[0]; while ((optc = getopt_long( argc, argv, "d::fhk::p::vw", long_options, NULL )) != -1) { switch(optc) { case 'd': if (optarg && isdigit(*optarg)) debug_level = atoi( optarg ); else debug_level++; break; case 'f': foreground = 1; break; case 'h': usage(); exit(0); break; case 'k': if (optarg && isdigit(*optarg)) ret = kill_lock_owner( atoi( optarg ) ); else ret = kill_lock_owner(-1); exit( !ret ); case 'p': if (optarg && isdigit(*optarg)) master_socket_timeout = (timeout_t)atoi( optarg ) * -TICKS_PER_SEC; else master_socket_timeout = TIMEOUT_INFINITE; break; case 'v': fprintf( stderr, "%s\n", wine_get_build_id()); exit(0); case 'w': wait_for_lock(); exit(0); default: usage(); exit(1); } } }
static void do_setup_dpll(u32 const base, const struct dpll_params *params, u8 lock, char *dpll) { u32 temp, M, N; struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; if (!params) return; temp = readl(&dpll_regs->cm_clksel_dpll); if (check_for_lock(base)) { /* * The Dpll has already been locked by rom code using CH. * Check if M,N are matching with Ideal nominal opp values. * If matches, skip the rest otherwise relock. */ M = (temp & CM_CLKSEL_DPLL_M_MASK) >> CM_CLKSEL_DPLL_M_SHIFT; N = (temp & CM_CLKSEL_DPLL_N_MASK) >> CM_CLKSEL_DPLL_N_SHIFT; if ((M != (params->m)) || (N != (params->n))) { debug("\n %s Dpll locked, but not for ideal M = %d," "N = %d values, current values are M = %d," "N= %d" , dpll, params->m, params->n, M, N); } else { /* Dpll locked with ideal values for nominal opps. */ debug("\n %s Dpll already locked with ideal" "nominal opp values", dpll); bypass_dpll(base); goto setup_post_dividers; } } bypass_dpll(base); /* Set M & N */ temp &= ~CM_CLKSEL_DPLL_M_MASK; temp |= (params->m << CM_CLKSEL_DPLL_M_SHIFT) & CM_CLKSEL_DPLL_M_MASK; temp &= ~CM_CLKSEL_DPLL_N_MASK; temp |= (params->n << CM_CLKSEL_DPLL_N_SHIFT) & CM_CLKSEL_DPLL_N_MASK; writel(temp, &dpll_regs->cm_clksel_dpll); setup_post_dividers: setup_post_dividers(base, params); /* Lock */ if (lock) do_lock_dpll(base); /* Wait till the DPLL locks */ if (lock) wait_for_lock(base); }
static void parse_args( int argc, char *argv[] ) { int i, ret; server_argv0 = argv[0]; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch(argv[i][1]) { case 'd': if (isdigit(argv[i][2])) debug_level = atoi( argv[i] + 2 ); else debug_level++; break; case 'f': foreground = 1; break; case 'h': usage(); exit(0); break; case 'k': if (isdigit(argv[i][2])) ret = kill_lock_owner( atoi(argv[i] + 2) ); else ret = kill_lock_owner(-1); exit( !ret ); case 'p': if (isdigit(argv[i][2])) master_socket_timeout = atoi( argv[i] + 2 ); else master_socket_timeout = -1; break; case 'v': fprintf( stderr, "%s\n", PACKAGE_STRING ); exit(0); case 'w': wait_for_lock(); exit(0); default: fprintf( stderr, "wineserver: unknown option '%s'\n", argv[i] ); usage(); exit(1); } } else { fprintf( stderr, "wineserver: unknown argument '%s'.\n", argv[i] ); usage(); exit(1); } } }
my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data) { THR_LOCK *lock=data->lock; DBUG_ENTER("thr_upgrade_write_delay_lock"); pthread_mutex_lock(&lock->mutex); if (data->type == TL_UNLOCK || data->type >= TL_WRITE_LOW_PRIORITY) { pthread_mutex_unlock(&lock->mutex); DBUG_RETURN(data->type == TL_UNLOCK); /* Test if Aborted */ } check_locks(lock,"before upgrading lock",0); /* TODO: Upgrade to TL_WRITE_CONCURRENT_INSERT in some cases */ data->type=TL_WRITE; /* Upgrade lock */ /* Check if someone has given us the lock */ if (!data->cond) { if (!lock->read.data) /* No read locks */ { /* We have the lock */ if (data->lock->get_status) (*data->lock->get_status)(data->status_param, 0); pthread_mutex_unlock(&lock->mutex); DBUG_RETURN(0); } if (((*data->prev)=data->next)) /* remove from lock-list */ data->next->prev= data->prev; else lock->write.last=data->prev; if ((data->next=lock->write_wait.data)) /* Put first in lock_list */ data->next->prev= &data->next; else lock->write_wait.last= &data->next; data->prev= &lock->write_wait.data; lock->write_wait.data=data; check_locks(lock,"upgrading lock",0); } else { check_locks(lock,"waiting for lock",0); } DBUG_RETURN(wait_for_lock(&lock->write_wait,data,1)); }
static void do_setup_dpll(u32 *const base, const struct dpll_params *params, u8 lock) { u32 temp; struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; bypass_dpll(base); /* Set M & N */ temp = readl(&dpll_regs->cm_clksel_dpll); temp &= ~CM_CLKSEL_DPLL_M_MASK; temp |= (params->m << CM_CLKSEL_DPLL_M_SHIFT) & CM_CLKSEL_DPLL_M_MASK; temp &= ~CM_CLKSEL_DPLL_N_MASK; temp |= (params->n << CM_CLKSEL_DPLL_N_SHIFT) & CM_CLKSEL_DPLL_N_MASK; writel(temp, &dpll_regs->cm_clksel_dpll); /* Lock */ if (lock) do_lock_dpll(base); /* Setup post-dividers */ if (params->m2 >= 0) writel(params->m2, &dpll_regs->cm_div_m2_dpll); if (params->m3 >= 0) writel(params->m3, &dpll_regs->cm_div_m3_dpll); if (params->m4 >= 0) writel(params->m4, &dpll_regs->cm_div_m4_dpll); if (params->m5 >= 0) writel(params->m5, &dpll_regs->cm_div_m5_dpll); if (params->m6 >= 0) writel(params->m6, &dpll_regs->cm_div_m6_dpll); if (params->m7 >= 0) writel(params->m7, &dpll_regs->cm_div_m7_dpll); /* Wait till the DPLL locks */ if (lock) wait_for_lock(base); }
enum enum_thr_lock_result thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, enum thr_lock_type lock_type) { THR_LOCK *lock=data->lock; enum enum_thr_lock_result result= THR_LOCK_SUCCESS; struct st_lock_list *wait_queue; THR_LOCK_DATA *lock_owner; DBUG_ENTER("thr_lock"); data->next=0; data->cond=0; /* safety */ data->type=lock_type; data->owner= owner; /* Must be reset ! */ VOID(pthread_mutex_lock(&lock->mutex)); DBUG_PRINT("lock",("data: 0x%lx thread: %ld lock: 0x%lx type: %d", (long) data, data->owner->info->thread_id, (long) lock, (int) lock_type)); check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ? "enter read_lock" : "enter write_lock",0); if ((int) lock_type <= (int) TL_READ_NO_INSERT) { /* Request for READ lock */ if (lock->write.data) { /* We can allow a read lock even if there is already a write lock on the table in one the following cases: - This thread alread have a write lock on the table - The write lock is TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED and the read lock is TL_READ_HIGH_PRIORITY or TL_READ - The write lock is TL_WRITE_CONCURRENT_INSERT or TL_WRITE_ALLOW_WRITE and the read lock is not TL_READ_NO_INSERT */ DBUG_PRINT("lock",("write locked by thread: %ld", lock->write.data->owner->info->thread_id)); if (thr_lock_owner_equal(data->owner, lock->write.data->owner) || (lock->write.data->type <= TL_WRITE_DELAYED && (((int) lock_type <= (int) TL_READ_HIGH_PRIORITY) || (lock->write.data->type != TL_WRITE_CONCURRENT_INSERT && lock->write.data->type != TL_WRITE_ALLOW_READ)))) { /* Already got a write lock */ (*lock->read.last)=data; /* Add to running FIFO */ data->prev=lock->read.last; lock->read.last= &data->next; if (lock_type == TL_READ_NO_INSERT) lock->read_no_write_count++; check_locks(lock,"read lock with old write lock",0); if (lock->get_status) (*lock->get_status)(data->status_param, 0); statistic_increment(locks_immediate,&THR_LOCK_lock); goto end; } if (lock->write.data->type == TL_WRITE_ONLY) { /* We are not allowed to get a READ lock in this case */ data->type=TL_UNLOCK; result= THR_LOCK_ABORTED; /* Can't wait for this one */ goto end; } } else if (!lock->write_wait.data || lock->write_wait.data->type <= TL_WRITE_LOW_PRIORITY || lock_type == TL_READ_HIGH_PRIORITY || have_old_read_lock(lock->read.data, data->owner)) { /* No important write-locks */ (*lock->read.last)=data; /* Add to running FIFO */ data->prev=lock->read.last; lock->read.last= &data->next; if (lock->get_status) (*lock->get_status)(data->status_param, 0); if (lock_type == TL_READ_NO_INSERT) lock->read_no_write_count++; check_locks(lock,"read lock with no write locks",0); statistic_increment(locks_immediate,&THR_LOCK_lock); goto end; } /* We're here if there is an active write lock or no write lock but a high priority write waiting in the write_wait queue. In the latter case we should yield the lock to the writer. */ wait_queue= &lock->read_wait; } else /* Request for WRITE lock */ { if (lock_type == TL_WRITE_DELAYED) { if (lock->write.data && lock->write.data->type == TL_WRITE_ONLY) { data->type=TL_UNLOCK; result= THR_LOCK_ABORTED; /* Can't wait for this one */ goto end; } /* if there is a TL_WRITE_ALLOW_READ lock, we have to wait for a lock (TL_WRITE_ALLOW_READ is used for ALTER TABLE in MySQL) */ if ((!lock->write.data || lock->write.data->type != TL_WRITE_ALLOW_READ) && !have_specific_lock(lock->write_wait.data,TL_WRITE_ALLOW_READ) && (lock->write.data || lock->read.data)) { /* Add delayed write lock to write_wait queue, and return at once */ (*lock->write_wait.last)=data; data->prev=lock->write_wait.last; lock->write_wait.last= &data->next; data->cond=get_cond(); /* We don't have to do get_status here as we will do it when we change the delayed lock to a real write lock */ statistic_increment(locks_immediate,&THR_LOCK_lock); goto end; } } else if (lock_type == TL_WRITE_CONCURRENT_INSERT && ! lock->check_status) data->type=lock_type= thr_upgraded_concurrent_insert_lock; if (lock->write.data) /* If there is a write lock */ { if (lock->write.data->type == TL_WRITE_ONLY) { /* We are not allowed to get a lock in this case */ data->type=TL_UNLOCK; result= THR_LOCK_ABORTED; /* Can't wait for this one */ goto end; } /* The following test will not work if the old lock was a TL_WRITE_ALLOW_WRITE, TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED in the same thread, but this will never happen within MySQL. */ if (thr_lock_owner_equal(data->owner, lock->write.data->owner) || (lock_type == TL_WRITE_ALLOW_WRITE && !lock->write_wait.data && lock->write.data->type == TL_WRITE_ALLOW_WRITE)) { /* We have already got a write lock or all locks are TL_WRITE_ALLOW_WRITE */ DBUG_PRINT("info", ("write_wait.data: 0x%lx old_type: %d", (ulong) lock->write_wait.data, lock->write.data->type)); (*lock->write.last)=data; /* Add to running fifo */ data->prev=lock->write.last; lock->write.last= &data->next; check_locks(lock,"second write lock",0); if (data->lock->get_status) (*data->lock->get_status)(data->status_param, 0); statistic_increment(locks_immediate,&THR_LOCK_lock); goto end; } DBUG_PRINT("lock",("write locked by thread: %ld", lock->write.data->owner->info->thread_id)); } else { DBUG_PRINT("info", ("write_wait.data: 0x%lx", (ulong) lock->write_wait.data)); if (!lock->write_wait.data) { /* no scheduled write locks */ my_bool concurrent_insert= 0; if (lock_type == TL_WRITE_CONCURRENT_INSERT) { concurrent_insert= 1; if ((*lock->check_status)(data->status_param)) { concurrent_insert= 0; data->type=lock_type= thr_upgraded_concurrent_insert_lock; } } if (!lock->read.data || (lock_type <= TL_WRITE_DELAYED && ((lock_type != TL_WRITE_CONCURRENT_INSERT && lock_type != TL_WRITE_ALLOW_WRITE) || !lock->read_no_write_count))) { (*lock->write.last)=data; /* Add as current write lock */ data->prev=lock->write.last; lock->write.last= &data->next; if (data->lock->get_status) (*data->lock->get_status)(data->status_param, concurrent_insert); check_locks(lock,"only write lock",0); statistic_increment(locks_immediate,&THR_LOCK_lock); goto end; } } DBUG_PRINT("lock",("write locked by thread: %ld type: %d", lock->read.data->owner->info->thread_id, data->type)); } wait_queue= &lock->write_wait; } /* Try to detect a trivial deadlock when using cursors: attempt to lock a table that is already locked by an open cursor within the same connection. lock_owner can be zero if we succumbed to a high priority writer in the write_wait queue. */ lock_owner= lock->read.data ? lock->read.data : lock->write.data; if (lock_owner && lock_owner->owner->info == owner->info) { result= THR_LOCK_DEADLOCK; goto end; } /* Can't get lock yet; Wait for it */ DBUG_RETURN(wait_for_lock(wait_queue, data, 0)); end: pthread_mutex_unlock(&lock->mutex); DBUG_RETURN(result); }
enum enum_thr_lock_result thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, enum thr_lock_type lock_type, ulong lock_wait_timeout, struct st_my_thread_var *thread_var) { THR_LOCK *lock=data->lock; enum enum_thr_lock_result result= THR_LOCK_SUCCESS; struct st_lock_list *wait_queue; MYSQL_TABLE_WAIT_VARIABLES(locker, state) /* no ';' */ DBUG_ENTER("thr_lock"); data->next=0; data->cond=0; /* safety */ data->type=lock_type; data->owner= owner; /* Must be reset ! */ MYSQL_START_TABLE_LOCK_WAIT(locker, &state, data->m_psi, PSI_TABLE_LOCK, lock_type); mysql_mutex_lock(&lock->mutex); DBUG_PRINT("lock",("data: 0x%lx thread: 0x%x lock: 0x%lx type: %d", (long) data, data->owner->thread_id, (long) lock, (int) lock_type)); check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ? "enter read_lock" : "enter write_lock",0); if ((int) lock_type <= (int) TL_READ_NO_INSERT) { /* Request for READ lock */ if (lock->write.data) { /* We can allow a read lock even if there is already a write lock on the table if they are owned by the same thread or if they satisfy the following lock compatibility matrix: Request /------- H|++++ WRITE_ALLOW_WRITE e|+++- WRITE_CONCURRENT_INSERT l |||| d |||| |||\= READ_NO_INSERT ||\ = READ_HIGH_PRIORITY |\ = READ_WITH_SHARED_LOCKS \ = READ + = Request can be satisified. - = Request cannot be satisified. READ_NO_INSERT and WRITE_ALLOW_WRITE should in principle be incompatible. Before this could have caused starvation of LOCK TABLE READ in InnoDB under high write load. However now READ_NO_INSERT is only used for LOCK TABLES READ and this statement is handled by the MDL subsystem. See Bug#42147 for more information. */ DBUG_PRINT("lock",("write locked 1 by thread: 0x%x", lock->write.data->owner->thread_id)); if (thr_lock_owner_equal(data->owner, lock->write.data->owner) || (lock->write.data->type < TL_WRITE_CONCURRENT_INSERT) || ((lock->write.data->type == TL_WRITE_CONCURRENT_INSERT) && ((int) lock_type <= (int) TL_READ_HIGH_PRIORITY))) { /* Already got a write lock */ (*lock->read.last)=data; /* Add to running FIFO */ data->prev=lock->read.last; lock->read.last= &data->next; if (lock_type == TL_READ_NO_INSERT) lock->read_no_write_count++; check_locks(lock,"read lock with old write lock",0); if (lock->get_status) (*lock->get_status)(data->status_param, 0); locks_immediate++; goto end; } if (lock->write.data->type == TL_WRITE_ONLY) { /* We are not allowed to get a READ lock in this case */ data->type=TL_UNLOCK; result= THR_LOCK_ABORTED; /* Can't wait for this one */ goto end; } } else if (!lock->write_wait.data || lock->write_wait.data->type <= TL_WRITE_LOW_PRIORITY || lock_type == TL_READ_HIGH_PRIORITY || has_old_lock(lock->read.data, data->owner)) /* Has old read lock */ { /* No important write-locks */ (*lock->read.last)=data; /* Add to running FIFO */ data->prev=lock->read.last; lock->read.last= &data->next; if (lock->get_status) (*lock->get_status)(data->status_param, 0); if (lock_type == TL_READ_NO_INSERT) lock->read_no_write_count++; check_locks(lock,"read lock with no write locks",0); locks_immediate++; goto end; } /* We're here if there is an active write lock or no write lock but a high priority write waiting in the write_wait queue. In the latter case we should yield the lock to the writer. */ wait_queue= &lock->read_wait; } else /* Request for WRITE lock */ { if (lock_type == TL_WRITE_CONCURRENT_INSERT && ! lock->check_status) data->type=lock_type= thr_upgraded_concurrent_insert_lock; if (lock->write.data) /* If there is a write lock */ { if (lock->write.data->type == TL_WRITE_ONLY) { /* purecov: begin tested */ /* Allow lock owner to bypass TL_WRITE_ONLY. */ if (!thr_lock_owner_equal(data->owner, lock->write.data->owner)) { /* We are not allowed to get a lock in this case */ data->type=TL_UNLOCK; result= THR_LOCK_ABORTED; /* Can't wait for this one */ goto end; } /* purecov: end */ } /* The idea is to allow us to get a lock at once if we already have a write lock or if there is no pending write locks and if all write locks are of TL_WRITE_ALLOW_WRITE type. Note that, since lock requests for the same table are sorted in such way that requests with higher thr_lock_type value come first (with one exception (*)), lock being requested usually has equal or "weaker" type than one which thread might have already acquired. *) The only exception to this rule is case when type of old lock is TL_WRITE_LOW_PRIORITY and type of new lock is changed inside of thr_lock() from TL_WRITE_CONCURRENT_INSERT to TL_WRITE since engine turns out to be not supporting concurrent inserts. Note that since TL_WRITE has the same compatibility rules as TL_WRITE_LOW_PRIORITY (their only difference is priority), it is OK to grant new lock without additional checks in such situation. Therefore it is OK to allow acquiring write lock on the table if this thread already holds some write lock on it. (INSERT INTO t1 VALUES (f1()), where f1() is stored function which tries to update t1, is an example of statement which requests two different types of write lock on the same table). */ DBUG_ASSERT(! has_old_lock(lock->write.data, data->owner) || ((lock_type <= lock->write.data->type || (lock_type == TL_WRITE && lock->write.data->type == TL_WRITE_LOW_PRIORITY)))); if ((lock_type == TL_WRITE_ALLOW_WRITE && ! lock->write_wait.data && lock->write.data->type == TL_WRITE_ALLOW_WRITE) || has_old_lock(lock->write.data, data->owner)) { /* We have already got a write lock or all locks are TL_WRITE_ALLOW_WRITE */ DBUG_PRINT("info", ("write_wait.data: 0x%lx old_type: %d", (ulong) lock->write_wait.data, lock->write.data->type)); (*lock->write.last)=data; /* Add to running fifo */ data->prev=lock->write.last; lock->write.last= &data->next; check_locks(lock,"second write lock",0); if (data->lock->get_status) (*data->lock->get_status)(data->status_param, 0); locks_immediate++; goto end; } DBUG_PRINT("lock",("write locked 2 by thread: 0x%x", lock->write.data->owner->thread_id)); } else { DBUG_PRINT("info", ("write_wait.data: 0x%lx", (ulong) lock->write_wait.data)); if (!lock->write_wait.data) { /* no scheduled write locks */ my_bool concurrent_insert= 0; if (lock_type == TL_WRITE_CONCURRENT_INSERT) { concurrent_insert= 1; if ((*lock->check_status)(data->status_param)) { concurrent_insert= 0; data->type=lock_type= thr_upgraded_concurrent_insert_lock; } } if (!lock->read.data || (lock_type <= TL_WRITE_CONCURRENT_INSERT && ((lock_type != TL_WRITE_CONCURRENT_INSERT && lock_type != TL_WRITE_ALLOW_WRITE) || !lock->read_no_write_count))) { (*lock->write.last)=data; /* Add as current write lock */ data->prev=lock->write.last; lock->write.last= &data->next; if (data->lock->get_status) (*data->lock->get_status)(data->status_param, concurrent_insert); check_locks(lock,"only write lock",0); locks_immediate++; goto end; } } DBUG_PRINT("lock",("write locked 3 by thread: 0x%x type: %d", lock->read.data->owner->thread_id, data->type)); } wait_queue= &lock->write_wait; } /* Can't get lock yet; Wait for it */ result= wait_for_lock(wait_queue, data, 0, lock_wait_timeout, thread_var); MYSQL_END_TABLE_LOCK_WAIT(locker); DBUG_RETURN(result); end: mysql_mutex_unlock(&lock->mutex); MYSQL_END_TABLE_LOCK_WAIT(locker); DBUG_RETURN(result); }
void lock_dpll(u32 const base) { do_lock_dpll(base); wait_for_lock(base); }
int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) { THR_LOCK *lock=data->lock; int result=0; DBUG_ENTER("thr_lock"); data->next=0; data->cond=0; /* safety */ data->type=lock_type; data->thread=pthread_self(); /* Must be reset ! */ data->thread_id=my_thread_id(); /* Must be reset ! */ VOID(pthread_mutex_lock(&lock->mutex)); DBUG_PRINT("lock",("data: %lx thread: %ld lock: %lx type: %d", data,data->thread_id,lock,(int) lock_type)); check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ? "enter read_lock" : "enter write_lock",0); if ((int) lock_type <= (int) TL_READ_NO_INSERT) { /* Request for READ lock */ if (lock->write.data) { /* We can allow a read lock even if there is already a write lock on the table in one the following cases: - This thread alread have a write lock on the table - The write lock is TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED and the read lock is TL_READ_HIGH_PRIORITY or TL_READ - The write lock is TL_WRITE_CONCURRENT_INSERT or TL_WRITE_ALLOW_WRITE and the read lock is not TL_READ_NO_INSERT */ DBUG_PRINT("lock",("write locked by thread: %ld", lock->write.data->thread_id)); if (pthread_equal(data->thread,lock->write.data->thread) || (lock->write.data->type <= TL_WRITE_DELAYED && (((int) lock_type <= (int) TL_READ_HIGH_PRIORITY) || (lock->write.data->type != TL_WRITE_CONCURRENT_INSERT && lock->write.data->type != TL_WRITE_ALLOW_READ)))) { /* Already got a write lock */ (*lock->read.last)=data; /* Add to running FIFO */ data->prev=lock->read.last; lock->read.last= &data->next; if ((int) lock_type == (int) TL_READ_NO_INSERT) lock->read_no_write_count++; check_locks(lock,"read lock with old write lock",0); if (lock->get_status) (*lock->get_status)(data->status_param); statistic_increment(locks_immediate,&THR_LOCK_lock); goto end; } if (lock->write.data->type == TL_WRITE_ONLY) { /* We are not allowed to get a READ lock in this case */ data->type=TL_UNLOCK; result=1; /* Can't wait for this one */ goto end; } } else if (!lock->write_wait.data || lock->write_wait.data->type <= TL_WRITE_LOW_PRIORITY || lock_type == TL_READ_HIGH_PRIORITY || have_old_read_lock(lock->read.data,data->thread)) { /* No important write-locks */ (*lock->read.last)=data; /* Add to running FIFO */ data->prev=lock->read.last; lock->read.last= &data->next; if (lock->get_status) (*lock->get_status)(data->status_param); if ((int) lock_type == (int) TL_READ_NO_INSERT) lock->read_no_write_count++; check_locks(lock,"read lock with no write locks",0); statistic_increment(locks_immediate,&THR_LOCK_lock); goto end; } /* Can't get lock yet; Wait for it */ DBUG_RETURN(wait_for_lock(&lock->read_wait,data,0)); } else /* Request for WRITE lock */ { if (lock_type == TL_WRITE_DELAYED) { if (lock->write.data && lock->write.data->type == TL_WRITE_ONLY) { data->type=TL_UNLOCK; result=1; /* Can't wait for this one */ goto end; } /* if there is a TL_WRITE_ALLOW_READ lock, we have to wait for a lock (TL_WRITE_ALLOW_READ is used for ALTER TABLE in MySQL) */ if ((!lock->write.data || lock->write.data->type != TL_WRITE_ALLOW_READ) && !have_specific_lock(lock->write_wait.data,TL_WRITE_ALLOW_READ) && (lock->write.data || lock->read.data)) { /* Add delayed write lock to write_wait queue, and return at once */ (*lock->write_wait.last)=data; data->prev=lock->write_wait.last; lock->write_wait.last= &data->next; data->cond=get_cond(); if (lock->get_status) (*lock->get_status)(data->status_param); statistic_increment(locks_immediate,&THR_LOCK_lock); goto end; } } else if (lock_type == TL_WRITE_CONCURRENT_INSERT && ! lock->check_status) data->type=lock_type= thr_upgraded_concurrent_insert_lock; if (lock->write.data) /* If there is a write lock */ { if (lock->write.data->type == TL_WRITE_ONLY) { /* We are not allowed to get a lock in this case */ data->type=TL_UNLOCK; result=1; /* Can't wait for this one */ goto end; } /* The following test will not work if the old lock was a TL_WRITE_ALLOW_WRITE, TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED in the same thread, but this will never happen within MySQL. */ if (pthread_equal(data->thread,lock->write.data->thread) || (lock_type == TL_WRITE_ALLOW_WRITE && !lock->write_wait.data && lock->write.data->type == TL_WRITE_ALLOW_WRITE)) { /* We have already got a write lock or all locks are TL_WRITE_ALLOW_WRITE */ (*lock->write.last)=data; /* Add to running fifo */ data->prev=lock->write.last; lock->write.last= &data->next; check_locks(lock,"second write lock",0); if (data->lock->get_status) (*data->lock->get_status)(data->status_param); statistic_increment(locks_immediate,&THR_LOCK_lock); goto end; } DBUG_PRINT("lock",("write locked by thread: %ld", lock->write.data->thread_id)); } else { if (!lock->write_wait.data) { /* no scheduled write locks */ if (lock_type == TL_WRITE_CONCURRENT_INSERT && (*lock->check_status)(data->status_param)) data->type=lock_type= thr_upgraded_concurrent_insert_lock; if (!lock->read.data || (lock_type <= TL_WRITE_DELAYED && ((lock_type != TL_WRITE_CONCURRENT_INSERT && lock_type != TL_WRITE_ALLOW_WRITE) || !lock->read_no_write_count))) { (*lock->write.last)=data; /* Add as current write lock */ data->prev=lock->write.last; lock->write.last= &data->next; if (data->lock->get_status) (*data->lock->get_status)(data->status_param); check_locks(lock,"only write lock",0); statistic_increment(locks_immediate,&THR_LOCK_lock); goto end; } } DBUG_PRINT("lock",("write locked by thread: %ld, type: %ld", lock->read.data->thread_id,data->type)); } DBUG_RETURN(wait_for_lock(&lock->write_wait,data,0)); } end: pthread_mutex_unlock(&lock->mutex); DBUG_RETURN(result); }
/* * Execute an arbitrary command while holding a file lock. */ int main(int argc, char **argv) { int ch, flags, silent, waitsec, i=0, cmdsize=1; pid_t child=1; if (argc==1) usage(); mailto=NULL; cmd=NULL; action=NULL; cmd=malloc(1); silent = keep = 0; flags = O_CREAT; waitsec = -1; /* Infinite. */ while ((ch = getopt(argc, argv, "+a:+c:+m:")) != -1) { switch (ch) { case 'a': action = malloc(strlen(optarg) + 1); memset(action, 0, strlen(optarg) + 1); strcpy(action, optarg); break; case 'c': chdir(optarg); break; case 'm': mailto = malloc(strlen(optarg) + 1); memset(mailto, 0, strlen(optarg) + 1); strcpy(mailto, optarg); break; case '?': default: break; } } //shift $0 argc -= optind; argv += optind; bzero(cmd,sizeof(cmd)); if (!mailto) { mailto = malloc(strlen(MAILTO)); memset(mailto, 0, strlen(MAILTO)); strcpy(mailto, MAILTO); } if (child != 0) { // this is parent (void)gettimeofday(&before, NULL); void * tmp = NULL; for (i=0; i< argc; i++) { cmdsize+=strlen(argv[i])+1; tmp = realloc(cmd, cmdsize); if ( tmp == NULL) { err(EX_OSERR,"realloc error"); } else { cmd = tmp; } strcat(cmd,argv[i]); strcat(cmd," "); } tmp = realloc(md5str,MD5_DIGEST_LENGTH * 2 + 2); //2 bytes from one MD5_Final + end string if ( tmp == NULL) { err(EX_OSERR,"realloc error"); } else { md5str = tmp; } unsigned char out[MD5_DIGEST_LENGTH]; MD5_CTX c; MD5_Init(&c); MD5_Update(&c, cmd, cmdsize); MD5_Final(out, &c); for(i=0; i<MD5_DIGEST_LENGTH; i++) { sprintf(md5str+(i*2),"%02x",out[i]); } lockname=malloc(strlen(md5str)+strlen(LOCKDIR)+strlen(LOCKFILE_POSTFIX)+2); // +2 "/ between dir/file" sprintf(lockname,"%s/%s%s",LOCKDIR,md5str,LOCKFILE_POSTFIX); } lockfd = acquire_lock(lockname, flags | O_NONBLOCK); while (lockfd == -1 && !timed_out && waitsec != 0) { if (keep) lockfd = acquire_lock(lockname, flags); else { wait_for_lock(lockname); lockfd = acquire_lock(lockname, flags | O_NONBLOCK); } } if (waitsec > 0) alarm(0); if (lockfd == -1) { /* We failed to acquire the lock. */ syslog(LOG_INFO, "Already locked (%s) %s\n", lockname, cmd); send_lock_alert(); free(cmd); free(md5str); if (silent) exit(EX_TEMPFAIL); errx(EX_TEMPFAIL, "%s: already locked", lockname); } /* At this point, we own the lock. */ if (atexit(cleanup) == -1) err(EX_OSERR, "atexit failed"); if ((child = fork()) == -1) err(EX_OSERR, "cannot fork"); if (child == 0) { /* The child process. */ close(lockfd); execvp(argv[0], argv); (void)gettimeofday(&after, NULL); warn("%s", argv[0]); _exit(1); } /* This is the parent process. */ signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGTERM, killed); if (waitpid(child, &status, 0) == -1) err(EX_OSERR, "waitpid failed"); status=WEXITSTATUS(status); return (WIFEXITED(status) ? WEXITSTATUS(status) : EX_SOFTWARE); }