Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 37267
b: refs/heads/master
c: 45289bf
h: refs/heads/master
i:
  37265: 3905e49
  37263: e60ce7a
v: v3
  • Loading branch information
Stefan Richter authored and Ben Collins committed Jul 3, 2006
1 parent 82958c4 commit c256a77
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 37 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 438bd525e5240a48233cd3290f7fe66ff0167e20
refs/heads/master: 45289bf6ac70b106f5000d10b040e4485dd3e9d5
3 changes: 1 addition & 2 deletions trunk/drivers/ieee1394/raw1394-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ struct file_info {

struct list_head req_pending;
struct list_head req_complete;
struct semaphore complete_sem;
spinlock_t reqlists_lock;
wait_queue_head_t poll_wait_complete;
wait_queue_head_t wait_complete;

struct list_head addr_list;

Expand Down
91 changes: 57 additions & 34 deletions trunk/drivers/ieee1394/raw1394.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,9 @@ static void free_pending_request(struct pending_request *req)
static void __queue_complete_req(struct pending_request *req)
{
struct file_info *fi = req->file_info;
list_move_tail(&req->list, &fi->req_complete);

up(&fi->complete_sem);
wake_up_interruptible(&fi->poll_wait_complete);
list_move_tail(&req->list, &fi->req_complete);
wake_up(&fi->wait_complete);
}

static void queue_complete_req(struct pending_request *req)
Expand Down Expand Up @@ -464,13 +463,36 @@ raw1394_compat_read(const char __user *buf, struct raw1394_request *r)

#endif

/* get next completed request (caller must hold fi->reqlists_lock) */
static inline struct pending_request *__next_complete_req(struct file_info *fi)
{
struct list_head *lh;
struct pending_request *req = NULL;

if (!list_empty(&fi->req_complete)) {
lh = fi->req_complete.next;
list_del(lh);
req = list_entry(lh, struct pending_request, list);
}
return req;
}

/* atomically get next completed request */
static struct pending_request *next_complete_req(struct file_info *fi)
{
unsigned long flags;
struct pending_request *req;

spin_lock_irqsave(&fi->reqlists_lock, flags);
req = __next_complete_req(fi);
spin_unlock_irqrestore(&fi->reqlists_lock, flags);
return req;
}

static ssize_t raw1394_read(struct file *file, char __user * buffer,
size_t count, loff_t * offset_is_ignored)
{
unsigned long flags;
struct file_info *fi = (struct file_info *)file->private_data;
struct list_head *lh;
struct pending_request *req;
ssize_t ret;

Expand All @@ -488,22 +510,21 @@ static ssize_t raw1394_read(struct file *file, char __user * buffer,
}

if (file->f_flags & O_NONBLOCK) {
if (down_trylock(&fi->complete_sem)) {
if (!(req = next_complete_req(fi)))
return -EAGAIN;
}
} else {
if (down_interruptible(&fi->complete_sem)) {
/*
* NB: We call the macro wait_event_interruptible() with a
* condition argument with side effect. This is only possible
* because the side effect does not occur until the condition
* became true, and wait_event_interruptible() won't evaluate
* the condition again after that.
*/
if (wait_event_interruptible(fi->wait_complete,
(req = next_complete_req(fi))))
return -ERESTARTSYS;
}
}

spin_lock_irqsave(&fi->reqlists_lock, flags);
lh = fi->req_complete.next;
list_del(lh);
spin_unlock_irqrestore(&fi->reqlists_lock, flags);

req = list_entry(lh, struct pending_request, list);

if (req->req.length) {
if (copy_to_user(int2ptr(req->req.recvb), req->data,
req->req.length)) {
Expand Down Expand Up @@ -2745,7 +2766,7 @@ static unsigned int raw1394_poll(struct file *file, poll_table * pt)
unsigned int mask = POLLOUT | POLLWRNORM;
unsigned long flags;

poll_wait(file, &fi->poll_wait_complete, pt);
poll_wait(file, &fi->wait_complete, pt);

spin_lock_irqsave(&fi->reqlists_lock, flags);
if (!list_empty(&fi->req_complete)) {
Expand All @@ -2770,9 +2791,8 @@ static int raw1394_open(struct inode *inode, struct file *file)
fi->state = opened;
INIT_LIST_HEAD(&fi->req_pending);
INIT_LIST_HEAD(&fi->req_complete);
sema_init(&fi->complete_sem, 0);
spin_lock_init(&fi->reqlists_lock);
init_waitqueue_head(&fi->poll_wait_complete);
init_waitqueue_head(&fi->wait_complete);
INIT_LIST_HEAD(&fi->addr_list);

file->private_data = fi;
Expand All @@ -2785,7 +2805,7 @@ static int raw1394_release(struct inode *inode, struct file *file)
struct file_info *fi = file->private_data;
struct list_head *lh;
struct pending_request *req;
int done = 0, i, fail = 0;
int i, fail;
int retval = 0;
struct list_head *entry;
struct arm_addr *addr = NULL;
Expand Down Expand Up @@ -2865,25 +2885,28 @@ static int raw1394_release(struct inode *inode, struct file *file)
"error(s) occurred \n");
}

while (!done) {
for (;;) {
/* This locked section guarantees that neither
* complete nor pending requests exist once i!=0 */
spin_lock_irqsave(&fi->reqlists_lock, flags);

while (!list_empty(&fi->req_complete)) {
lh = fi->req_complete.next;
list_del(lh);

req = list_entry(lh, struct pending_request, list);

while ((req = __next_complete_req(fi)))
free_pending_request(req);
}

if (list_empty(&fi->req_pending))
done = 1;

i = list_empty(&fi->req_pending);
spin_unlock_irqrestore(&fi->reqlists_lock, flags);

if (!done)
down_interruptible(&fi->complete_sem);
if (i)
break;
/*
* Sleep until more requests can be freed.
*
* NB: We call the macro wait_event() with a condition argument
* with side effect. This is only possible because the side
* effect does not occur until the condition became true, and
* wait_event() won't evaluate the condition again after that.
*/
wait_event(fi->wait_complete, (req = next_complete_req(fi)));
free_pending_request(req);
}

/* Remove any sub-trees left by user space programs */
Expand Down

0 comments on commit c256a77

Please sign in to comment.