Exemplo n.º 1
0
inline void remove_if_can_lock_file(const char *file_path)
{
   file_handle_t fhnd = open_existing_file(file_path, read_write);

   if(fhnd != invalid_file()){
      bool acquired;
      if(try_acquire_file_lock(fhnd, acquired) && acquired){
         delete_file(file_path);
      }
      close_file(fhnd);
   }
}
Exemplo n.º 2
0
   robust_mutex_lock_file()
   {
      permissions p;
      p.set_unrestricted();
      //Remove old lock files of other processes
      remove_old_robust_lock_files();
      //Create path and obtain lock file path for this process
      create_and_get_robust_lock_file_path(fname, get_current_process_id());

      //Now try to open or create the lock file
      fd = create_or_open_file(fname.c_str(), read_write, p);
      //If we can't open or create it, then something unrecoverable has happened
      if(fd == invalid_file()){
         throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: could not open or create file");
      }

      //Now we must take in care a race condition with another process
      //calling "remove_old_robust_lock_files()". No other threads from this
      //process will be creating the lock file because intermodule_singleton
      //guarantees this. So let's loop acquiring the lock and checking if we
      //can't exclusively create the file (if the file is erased by another process
      //then this exclusive open would fail). If the file can't be exclusively created
      //then we have correctly open/create and lock the file. If the file can
      //be exclusively created, then close previous locked file and try again.
      while(1){
         bool acquired;
         if(!try_acquire_file_lock(fd, acquired) || !acquired ){
            throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: try_acquire_file_lock");
         }
         //Creating exclusively must fail with already_exists_error
         //to make sure we've locked the file and no one has
         //deleted it between creation and locking
         file_handle_t fd2 = create_new_file(fname.c_str(), read_write, p);
         if(fd2 != invalid_file()){
            close_file(fd);
            fd = fd2;
            continue;
         }
         //If exclusive creation fails with expected error go ahead
         else if(error_info(system_error_code()).get_error_code() == already_exists_error){ //must already exist
            //Leak descriptor to mantain the file locked until the process dies
            break;
         }
         //If exclusive creation fails with unexpected error throw an unrecoverable error
         else{
            close_file(fd);
            throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: create_file filed with unexpected error");
         }
      }
   }
Exemplo n.º 3
0
inline bool robust_spin_mutex<Mutex>::is_owner_dead(boost::uint32_t own)
{
   //If owner is an invalid id, then it's clear it's dead
   if(own == (boost::uint32_t)get_invalid_process_id()){
      return true;
   }

   //Obtain the lock filename of the owner field
   std::string file;
   this->owner_to_filename(own, file);

   //Now the logic is to open and lock it
   file_handle_t fhnd = open_existing_file(file.c_str(), read_write);

   if(fhnd != invalid_file()){
      //If we can open the file, lock it.
      bool acquired;
      if(try_acquire_file_lock(fhnd, acquired) && acquired){
         //If locked, just delete the file
         delete_file(file.c_str());
         close_file(fhnd);
         return true;
      }
      //If not locked, the owner is suppossed to be still alive
      close_file(fhnd);
   }
   else{
      //If the lock file does not exist then the owner is dead (a previous cleanup)
      //function has deleted the file. If there is another reason, then this is
      //an unrecoverable error
      if(error_info(system_error_code()).get_error_code() == not_found_error){
         return true;
      }
   }
   return false;
}
Exemplo n.º 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

	// 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;
}