int acquire_a_local_lock(state_type *state, time_type timeout, int timeout_event_type, event_content_type *event_content, double now) {
	SERVER_lp_state_type *pointer = &state->type.server_state;
	if (pointer->configuration.cc_verbose)
		printf("cc%d - oggetto %d per la transizione %i da lockare\n", pointer->server_id, event_content->applicative_content.object_key_id, event_content->applicative_content.tx_id);
	//check lock...
	if (pointer->cc_metadata->locks[event_content->applicative_content.object_key_id] == -1) {
		//not locked
		pointer->cc_metadata->lock_retry_num = 0;
		//acquire lock
		pointer->cc_metadata->locks[event_content->applicative_content.object_key_id] = event_content->applicative_content.tx_id;
		if (pointer->configuration.cc_verbose)
			printf("cc%d - oggetto %d per la transizione %i lockato al tempo %f \n", pointer->server_id, event_content->applicative_content.object_key_id, event_content->applicative_content.tx_id,
					now);
		return 1;
	} else if (pointer->cc_metadata->locks[event_content->applicative_content.object_key_id] == event_content->applicative_content.tx_id) {
		// already locked by me
		return 1;
	} else {
		//already locked by another transaction
		pointer->cc_metadata->lock_retry_num++;
		//check deadlocks (if enabled)
		if (pointer->configuration.deadlock_detection_enabled && check_deadlock(event_content, pointer)) {
			return -1;
		}

		//add the timeout event
		event_content_type new_event_content;
		memcpy(&new_event_content, event_content, sizeof(event_content_type));
		ScheduleNewEvent(pointer->server_id, now + timeout, timeout_event_type, &new_event_content, sizeof(event_content_type));

		//enqueue event
		memcpy(&new_event_content, event_content, sizeof(event_content_type));
		new_event_content.applicative_content.object_key_id = event_content->applicative_content.object_key_id;
		enqueue_event(pointer, &new_event_content);

		transaction_metadata *transaction = get_transaction_metadata(event_content->applicative_content.tx_id, pointer);
		if (transaction == NULL) {
			if (pointer->configuration.cc_verbose) {
				printf("cc%d - la tx %i non è locale\n", pointer->server_id, event_content->applicative_content.tx_id);
				printf("cc%d - prepare of tx %i added in the waiting event queue %f due to a lock on object :%d tx:%i\n", pointer->server_id, event_content->applicative_content.tx_id, now,
						event_content->applicative_content.object_key_id, new_event_content.applicative_content.tx_id);
			}
			return 0;
		} else {
			transaction->is_blocked = 1;
			if (pointer->configuration.cc_verbose)
				printf("cc%d - tx %i is waiting at time %f due to a lock lock on object :%d tx:%i\n", pointer->server_id, event_content->applicative_content.tx_id, now,
						event_content->applicative_content.object_key_id, new_event_content.applicative_content.tx_id);
			return 0;
		}
	}
}
Exemple #2
0
/*
 * osprd_ioctl(inode, filp, cmd, arg)
 *   Called to perform an ioctl on the named file.
 */
int osprd_ioctl(struct inode *inode, struct file *filp,
		unsigned int cmd, unsigned long arg)
{
	osprd_info_t *d = file2osprd(filp);	// device info
	int r = 0;			// return value: initially 0

	// Set 'r' to the ioctl's return value: 0 on success, negative on error

	if (cmd == OSPRDIOCACQUIRE) {

		// EXERCISE: Lock the ramdisk.
		//
		// If *filp is open for writing (filp_writable), then attempt
		// to write-lock the ramdisk; otherwise attempt to read-lock
		// the ramdisk.
		//
        // This lock request must block using 'd->blockq' until:
		// 1) no other process holds a write lock;
		// 2) either the request is for a read lock, or no other process
		//    holds a read lock; and
		// 3) lock requests should be serviced in order, so no process
		//    that blocked earlier is still blocked waiting for the
		//    lock.
		//
		// If a process acquires a lock, mark this fact by setting
		// 'filp->f_flags |= F_OSPRD_LOCKED'.  You also need to
		// keep track of how many read and write locks are held:
		// change the 'osprd_info_t' structure to do this.
		//
		// Also wake up processes waiting on 'd->blockq' as needed.
		//
		// If the lock request would cause a deadlock, return -EDEADLK.
		// If the lock request blocks and is awoken by a signal, then
		// return -ERESTARTSYS.
		// Otherwise, if we can grant the lock request, return 0.

		// 'd->ticket_head' and 'd->ticket_tail' should help you
		// service lock requests in order.  These implement a ticket
		// order: 'ticket_tail' is the next ticket, and 'ticket_head'
		// is the ticket currently being served.  You should set a local
		// variable to 'd->ticket_head' and increment 'd->ticket_head'.
		// Then, block at least until 'd->ticket_tail == local_ticket'.
		// (Some of these operations are in a critical section and must
		// be protected by a spinlock; which ones?)

    // Used to track the current request
    unsigned local_ticket;

    if(check_deadlock(d))
		return -EDEADLK;

    // If we can't acquire the lock we put ourselves in the back of the queue
    // when the lock is released ticket_head will be incremented and we'll be
    // woken up
    while(try_acquire_file_lock(filp) != 0)
    {
      spin_lock(&d->mutex);
      d->ticket_tail++;
      local_ticket = d->ticket_tail;
      d->lock_waiter_l = list_add_to_front(d->lock_waiter_l, current->pid);
      spin_unlock(&d->mutex);

      wait_event_interruptible(d->blockq, d->ticket_head == local_ticket || d->num_to_requeue > 0);

      spin_lock(&d->mutex);
      d->lock_waiter_l = list_remove_element(d->lock_waiter_l, current->pid);
      spin_unlock(&d->mutex);

      // process any pending signals by re-queueing everything
      if(d->num_to_requeue > 0)
      {
        // Note: do NOT wake threads here, each thread should requeue only ONCE
        spin_lock(&d->mutex);
        d->num_to_requeue--;
        spin_unlock(&d->mutex);

        // If we find another pending signal, dispatch that too
        if(signal_pending(current))
          return -ERESTARTSYS;
      }
      else if(signal_pending(current)) // See if we were woken up by a signal
      {
        // For simplicity, we requeue all waiting tasks (-1 which
        // is the process) being "popped" off the wait queue
        spin_lock(&d->mutex);
        d->num_to_requeue = (d->ticket_tail - d->ticket_head - 1);
        d->ticket_head = 0;
        d->ticket_tail = 0;

        // All threads are woken to notify them of requeuing
        // meanwhile, we wait until that finishes (no need to check
        // for more interrupts, the process will exit anyway).
        wake_up_all(&d->blockq);
        spin_unlock(&d->mutex);

        // Sanity check
        if(d->num_to_requeue > 0)
        {
          wait_event(d->blockq, d->num_to_requeue == 0);
          wake_up_all(&d->blockq); // Wake everyone up again to check for other pending signals
        }
        return -ERESTARTSYS;
      }
    }

    r = 0;

	} else if (cmd == OSPRDIOCTRYACQUIRE) {

		// EXERCISE: ATTEMPT to lock the ramdisk.
		//
		// This is just like OSPRDIOCACQUIRE, except it should never
		// block.  If OSPRDIOCACQUIRE would block or return deadlock,
		// OSPRDIOCTRYACQUIRE should return -EBUSY.
		// Otherwise, if we can grant the lock request, return 0.

    r = try_acquire_file_lock(filp);

    if(r == -EDEADLK)
		r = -EBUSY;

	} else if (cmd == OSPRDIOCRELEASE) {

		// EXERCISE: Unlock the ramdisk.
		//
		// If the file hasn't locked the ramdisk, return -EINVAL.
		// Otherwise, clear the lock from filp->f_flags, wake up
		// the wait queue, perform any additional accounting steps
		// you need, and return 0.

		r = release_file_lock(filp);

	} else
		r = -ENOTTY; /* unknown command */
	return r;
}
int acquire_local_locks(state_type *state, data_set_entry *data_set, time_type timeout, int timeout_event_type, event_content_type *event_content, double now) {
	SERVER_lp_state_type *pointer = &state->type.server_state;
	data_set_entry *entry = data_set;
	if (entry == NULL) {
		if (pointer->configuration.cc_verbose)
			printf("cc%d -  write set of transaction %d is empty\n", pointer->server_id, event_content->applicative_content.tx_id);
		return 1;
	}
	while (entry != NULL) {
		int need_to_lock = 0;
		if (pointer->configuration.concurrency_control_type == ETL_2PL || pointer->configuration.concurrency_control_type == CTL_2PL)
			need_to_lock = is_owner(entry->object_key_id, pointer->server_id, state->num_servers, state->num_clients, state->object_replication_degree);
		else if (pointer->configuration.concurrency_control_type == PRIMARY_OWNER_CTL_2PL)
			need_to_lock = is_primary(entry->object_key_id, pointer->server_id, state->num_servers, state->num_clients);
		if (need_to_lock) {
			if (pointer->configuration.cc_verbose)
				printf("cc%d - object %d for transaction %i to be locked\n", pointer->server_id, entry->object_key_id, event_content->applicative_content.tx_id);
			//check lock...
			if (pointer->cc_metadata->locks[entry->object_key_id] == -1) {
				//not locked
				pointer->cc_metadata->lock_retry_num = 0;
				//acquire lock
				pointer->cc_metadata->locks[entry->object_key_id] = event_content->applicative_content.tx_id;
				if (pointer->configuration.cc_verbose)
					printf("cc%d - pbject %d  for transaction  %i locked at time %f \n", pointer->server_id, entry->object_key_id, event_content->applicative_content.tx_id, now);
			} else if (pointer->cc_metadata->locks[entry->object_key_id] == event_content->applicative_content.tx_id) {
				// already locked by me
				// go to the next entry
			} else {
				//already locked by another transaction
				pointer->cc_metadata->lock_retry_num++;
				//check deadlock (if enabled)
				if (pointer->configuration.deadlock_detection_enabled && check_deadlock(event_content, pointer)) {
					return -1;
				}
				//add the timeout event
				event_content_type new_event_content;
				memcpy(&new_event_content, event_content, sizeof(event_content_type));
				ScheduleNewEvent(pointer->server_id, now + timeout, timeout_event_type, &new_event_content, sizeof(event_content_type));

				//enqueue transaction
				memcpy(&new_event_content, event_content, sizeof(event_content_type));
				new_event_content.applicative_content.object_key_id = entry->object_key_id;
				enqueue_event(pointer, &new_event_content);

				transaction_metadata *transaction = get_transaction_metadata(event_content->applicative_content.tx_id, pointer);
				if (transaction == NULL) {
					if (pointer->configuration.cc_verbose) {
						printf("cc%d - transaction %i is not local\n", pointer->server_id, event_content->applicative_content.tx_id);
						printf("cc%d - prepare of tx %i added in the waiting event queue %f due to a lock on object %d tx:%i\n", pointer->server_id, event_content->applicative_content.tx_id, now,
								entry->object_key_id, new_event_content.applicative_content.tx_id);
					}
					return 0;
				} else {
					transaction->is_blocked = 1;
					if (pointer->configuration.cc_verbose)
						printf("cc%d - transaction %i is waiting at time %f due to a lock on object%d tx:%i\n", pointer->server_id, event_content->applicative_content.tx_id, now, entry->object_key_id,
								new_event_content.applicative_content.tx_id);
					return 0;
				}
			}
		}
		entry = entry->next;
	}
	return 1;
}
Exemple #4
0
/*
 * osprd_ioctl(inode, filp, cmd, arg)
 *   Called to perform an ioctl on the named file.
 */
int osprd_ioctl(struct inode *inode, struct file *filp,
		unsigned int cmd, unsigned long arg)
{
	osprd_info_t *d = file2osprd(filp);	// device info
	int r = 0;			// return value: initially 0

	// is file open for writing?
	int filp_writable = (filp->f_mode & FMODE_WRITE) != 0;

	// Set 'r' to the ioctl's return value: 0 on success, negative on error

	if (cmd == OSPRDIOCACQUIRE) {

		// EXERCISE: Lock the ramdisk.
		//
		// If *filp is open for writing (filp_writable), then attempt
		// to write-lock the ramdisk; otherwise attempt to read-lock
		// the ramdisk.
		//
                // This lock request must block using 'd->blockq' until:
		// 1) no other process holds a write lock;
		// 2) either the request is for a read lock, or no other process
		//    holds a read lock; and
		// 3) lock requests should be serviced in order, so no process
		//    that blocked earlier is still blocked waiting for the
		//    lock.
		//
		// If a process acquires a lock, mark this fact by setting
		// 'filp->f_flags |= F_OSPRD_LOCKED'.  You also need to
		// keep track of how many read and write locks are held:
		// change the 'osprd_info_t' structure to do this.
		//
		// Also wake up processes waiting on 'd->blockq' as needed.
		//
		// If the lock request would cause a deadlock, return -EDEADLK.
		// If the lock request blocks and is awoken by a signal, then
		// return -ERESTARTSYS.
		// Otherwise, if we can grant the lock request, return 0.

		// 'd->ticket_head' and 'd->ticket_tail' should help you
		// service lock requests in order.  These implement a ticket
		// order: 'ticket_tail' is the next ticket, and 'ticket_head'
		// is the ticket currently being served.  You should set a local
		// variable to 'd->ticket_head' and increment 'd->ticket_head'.
		// Then, block at least until 'd->ticket_tail == local_ticket'.
		// (Some of these operations are in a critical section and must
		// be protected by a spinlock; which ones?)

		int ticket;
		osp_spin_lock(&(d->mutex));
		ticket = d->ticket_head++;		
		if (d->ticket_tail != ticket) {
			osp_spin_unlock(&(d->mutex));
			if (wait_event_interruptible(d->blockq, d->ticket_tail == ticket) == -ERESTARTSYS) {
			        d->ticket_tail++;
				wake_up_all(&(d->blockq));
				return -ERESTARTSYS;
			}
		}
		else {
			osp_spin_unlock(&(d->mutex));
		}
		
		if (d->write_lock == 1) {
			for_each_open_file (current, add_dependencies, d);
			
 			if (check_deadlock()) {
				release_dependencies(d);
			        d->ticket_tail++;
				wake_up_all(&(d->blockq));
				return -EDEADLK;
			}
			if (wait_event_interruptible(d->blockq, d->write_lock == 0) == -ERESTARTSYS) {
				release_dependencies(d);
			        d->ticket_tail++;
				wake_up_all(&(d->blockq));	
				return -ERESTARTSYS;
			}
			release_dependencies(d);		
		}
		
		if (filp_writable) {
			if (d->read_lock > 0) {
				for_each_open_file (current, add_dependencies, d);
				
				if (check_deadlock()) {
					release_dependencies(d);
               			        d->ticket_tail++;
					wake_up_all(&(d->blockq));
					return -EDEADLK;
				}
				if (wait_event_interruptible(d->blockq, d->read_lock == 0) == -ERESTARTSYS) {
				        release_dependencies(d);
				        d->ticket_tail++;
					wake_up_all(&(d->blockq));
				        return -ERESTARTSYS;
				}

				release_dependencies(d);					
			}
			d->write_lock = 1;
		} 
		else {
			osp_spin_lock(&(d->mutex));
			d->read_lock++;
			osp_spin_unlock(&(d->mutex));
		}
		
		filp->f_flags |= F_OSPRD_LOCKED;
		
		osp_spin_lock(&(d->mutex));
		d->ticket_tail++;
		osp_spin_unlock(&(d->mutex));

		wake_up_all(&(d->blockq));
		
		r = 0;
		
	} else if (cmd == OSPRDIOCTRYACQUIRE) {
		
		// EXERCISE: ATTEMPT to lock the ramdisk.
		//
		// This is just like OSPRDIOCACQUIRE, except it should never
		// block.  If OSPRDIOCACQUIRE would block or return deadlock,
		// OSPRDIOCTRYACQUIRE should return -EBUSY.
		// Otherwise, if we can grant the lock request, return 0.
		osp_spin_lock(&(d->mutex));
		
		if (d->ticket_tail != d->ticket_head) {
			osp_spin_unlock(&(d->mutex));
			return -EBUSY;
		}

		d->ticket_head++;
		osp_spin_unlock(&(d->mutex));

		if (d->write_lock == 1) {
			d->ticket_tail++;
			wake_up_all(&(d->blockq));
			return -EBUSY;
		}
		
		if (filp_writable) {
			if (d->read_lock > 0) {
				d->ticket_tail++;
				wake_up_all(&(d->blockq));
				return -EBUSY;
			}
			d->write_lock = 1;
		} 
		else {
			osp_spin_lock(&(d->mutex));
			d->read_lock++;
			osp_spin_unlock(&(d->mutex));
		}
		
		filp->f_flags |= F_OSPRD_LOCKED;
		d->ticket_tail++;
		wake_up_all(&(d->blockq));
		r = 0;		

	} else if (cmd == OSPRDIOCRELEASE) {
		
		// EXERCISE: Unlock the ramdisk.
		//
		// If the file hasn't locked the ramdisk, return -EINVAL.
		// Otherwise, clear the lock from filp->f_flags, wake up
		// the wait queue, perform any additional accounting steps
		// you need, and return 0.
		
		if (filp->f_flags & F_OSPRD_LOCKED) {
			if (filp_writable) {
				if (d->write_lock == 1) d->write_lock = 0;
				else return -EINVAL;			
			}
			else {
				osp_spin_lock(&(d->mutex));
				
				if (d->read_lock > 0) d->read_lock--;
				else {
  				        osp_spin_unlock(&(d->mutex));				        
				        return -EINVAL;
				}
				osp_spin_unlock(&(d->mutex));
			}			
			
			filp->f_flags &= ~F_OSPRD_LOCKED;
			wake_up_all(&(d->blockq));
		
                        r = 0;			
		} else {
			r = -EINVAL;
		}
		
	} else
		r = -ENOTTY; /* unknown command */
	return r;
}
Exemple #5
0
int osprd_ioctl(struct inode *inode, struct file *filp,
		unsigned int cmd, unsigned long arg)
{
	osprd_info_t *d = file2osprd(filp);	// device info
	int r = 0;			// return value: initially 0
	unsigned cur_ticket;
	// is file open for writing?
	int filp_writable = (filp->f_mode & FMODE_WRITE) != 0;

	// This line avoids compiler warnings; you may remove it.
	(void) filp_writable, (void) d;

	// Set 'r' to the ioctl's return value: 0 on success, negative on error

	eprintk("%d\n", (int)current->pid);
	if (cmd == OSPRDIOCACQUIRE) {

		// EXERCISE: Lock the ramdisk.
		osp_spin_lock(&d->mutex);
		
		if (check_deadlock(d)) 
		{
			//osp_spin_unlock(&d->mutex);
			//return -EDEADLK;
			r = -EDEADLK;
		}
		else

		{
			add_check_deadlock_list(current->pid, d);
			eprintk ("add_check_deadlock_list");
			cur_ticket = d->ticket_head;
			d->ticket_head ++ ;
		}
		osp_spin_unlock(&d->mutex);
		if (r != 0) {
			return r;
		}

		if(filp_writable)
		{
			//osp_spin_lock(&d->mutex);	
			int w = wait_event_interruptible(d->blockq, (d->number_write_lock==0&&d->number_read_lock==0&&cur_ticket==d->ticket_tail));
			//Blocks the current task on a wait queue until a CONDITION becomes true. 
			//A request for a write lock on a ramdisk file will block until no other files on that 
			//ramdisk have a read or writeloc
			if(w == -ERESTARTSYS)
			{
				osp_spin_lock(&d->mutex);	
				//if the process is interrupted by signal
				if (cur_ticket == d->ticket_tail)
					d->ticket_tail++;
				//already in the next avalable ticket
				else
					d->ticket_head--;
				//destory this ticket
				osp_spin_unlock(&d->mutex);	
				return w;
			}
			
			osp_spin_lock(&d->mutex);	
			//Acquire a mutex (lock the mutex)
			d->ticket_tail++;
			d->write_lock_holder = current->pid;
			d->number_write_lock = 1;
			filp->f_flags |= F_OSPRD_LOCKED;
			osp_spin_unlock(&d->mutex);	
			//Release (unlock) the mutex
		}
		else
		{

			int w = wait_event_interruptible(d->blockq, (d->number_write_lock==0&&cur_ticket==d->ticket_tail));
			//Blocks the current task on a wait queue until a CONDITION becomes true. 
			//A request for a write lock on a ramdisk file will block until no other files on that 
			//ramdisk have a read or writeloc
			if(w == -ERESTARTSYS)
			{
				osp_spin_lock(&d->mutex);
				//if the process is interrupted by signal
				if (cur_ticket == d->ticket_tail)
					d->ticket_tail++;
				//already in the next avalable ticket
				else
					d->ticket_head--;
				osp_spin_unlock(&d->mutex);	
				//destory this ticket
				return w;
			}
			
			osp_spin_lock(&d->mutex);	
			//Acquire a mutex (lock the mutex)
			d->ticket_tail++;
			add_read_pid(current->pid,d);
			d->number_read_lock++;
			filp->f_flags |= F_OSPRD_LOCKED;
			osp_spin_unlock(&d->mutex);	
			//Release (unlock) the mutex
		}

	} else if (cmd == OSPRDIOCTRYACQUIRE) {

		// EXERCISE: ATTEMPT to lock the ramdisk.
		//
		// This is just like OSPRDIOCACQUIRE, except it should never
		// block.  If OSPRDIOCACQUIRE would block or return deadlock,
		// OSPRDIOCTRYACQUIRE should return -EBUSY.
		// Otherwise, if we can grant the lock request, return 0.

		// Your code here (instead of the next two lines).
		if (filp_writable)
		{
			//atomically acquire write lock
			osp_spin_lock (&d->mutex);	//atomicity
			if ((d->number_read_lock >0) || (d->number_write_lock>0))
			{
				osp_spin_unlock (&d->mutex);
				return -EBUSY;
			}
			else 	//d->number_read_lock ==0) && (d->number_write_lock==0)
			{
				d->write_lock_holder = current->pid;
				d->number_write_lock ++;
				d->ticket_tail++;
				d->ticket_head++;
				filp -> f_flags |= F_OSPRD_LOCKED;
				osp_spin_unlock (&d->mutex);
			}
		}
		else 	//opened for read 
		{
			//atomically acquire read lock
			osp_spin_lock (&d->mutex);
			{
				if (d->number_write_lock>0)		//can't get read lock
				{
					osp_spin_unlock(&d->mutex);
					return -EBUSY;
				}
				else
				{
					add_read_pid (current->pid,d);
					d->number_read_lock++;
					d->ticket_tail++;
					d->ticket_head++;
					filp -> f_flags |= F_OSPRD_LOCKED;
					osp_spin_unlock (&d->mutex);
				}
			}
		}

		
		//eprintk("Attempting to try acquire\n");
		//r = -ENOTTY;

	} else if (cmd == OSPRDIOCRELEASE) {

		// EXERCISE: Unlock the ramdisk.
		//
		// If the file hasn't locked the ramdisk, return -EINVAL.
		// Otherwise, clear the lock from filp->f_flags, wake up
		// the wait queue, perform any additional accounting steps
		// you need, and return 0.
		//osp_spin_lock (&d->mutex);
		if ((filp->f_flags & F_OSPRD_LOCKED)==0)
		{
			//osp_spin_unlock (&d->mutex);
			return -EINVAL;
		}
		else
		{
			osp_spin_lock (&d->mutex);	
			d->check_deadlock_list_head = list_remove_element(d->check_deadlock_list_head,current->pid);
			if (filp_writable)		//release the write locker
			{
				d->write_lock_holder = -1;
				d->number_write_lock --;
			}
			else 	//release the read locker
			{
				d->number_read_lock --;
				d->pid_list_head = list_remove_element(d->pid_list_head,current->pid);
				/*if (list_free_all (pid_list_head) == -ENOTTY)
					return -ENOTTY;*/
				if (d->pid_list_head == NULL)
					return -ENOTTY;
			}
			filp->f_flags &= ~F_OSPRD_LOCKED; 
			
			osp_spin_unlock (&d->mutex);
			wake_up_all (&d->blockq);

		}
		// Your code here (instead of the next line).
		//r = -ENOTTY;

	}
	else
		r = -ENOTTY; /* unknown command */
	return r;

}