All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nadia Derbey <Nadia.Derbey@bull.net>
To: Manfred Spraul <manfred@colorfullife.com>
Cc: linux-kernel@vger.kernel.org
Subject: Re: [PATCH 3/4] ipc/sem.c: convert sem_array.sem_pending to struct list_head
Date: Thu, 29 May 2008 17:06:59 +0200	[thread overview]
Message-ID: <483EC693.7030808@bull.net> (raw)
In-Reply-To: <200805241638.m4OGc4L5006320@mail.q-ag.de>

Manfred Spraul wrote:
> sem_array.sem_pending is a double linked list, the attached
> patch converts it to struct list_head.
> 
> Signed-Off-By: Manfred Spraul <manfred@colorfullife.com>

Reviewed-By: Nadia Derbey <Nadia.Derbey@bull.net>

2 small comments embedded.

> ---
>  include/linux/sem.h |   12 +++----
>  ipc/sem.c           |   90 ++++++++++++++++++--------------------------------
>  2 files changed, 38 insertions(+), 64 deletions(-)
> 
> diff --git a/include/linux/sem.h b/include/linux/sem.h
> index 87756ef..d425993 100644
> --- a/include/linux/sem.h
> +++ b/include/linux/sem.h
> @@ -93,21 +93,19 @@ struct sem_array {
>  	time_t			sem_otime;	/* last semop time */
>  	time_t			sem_ctime;	/* last change time */
>  	struct sem		*sem_base;	/* ptr to first semaphore in array */
> -	struct sem_queue	*sem_pending;	/* pending operations to be processed */
> -	struct sem_queue	**sem_pending_last; /* last pending operation */
> +	struct list_head	sem_pending;	/* pending operations to be processed */
>  	struct list_head	list_id;	/* undo requests on this array */
>  	unsigned long		sem_nsems;	/* no. of semaphores in array */
>  };
>  
>  /* One queue for each sleeping process in the system. */
>  struct sem_queue {
> -	struct sem_queue *	next;	 /* next entry in the queue */
> -	struct sem_queue **	prev;	 /* previous entry in the queue, *(q->prev) == q */
> -	struct task_struct*	sleeper; /* this process */
> -	struct sem_undo *	undo;	 /* undo structure */
> +	struct list_head	list;	 /* queue of pending operations */
> +	struct task_struct	*sleeper; /* this process */
> +	struct sem_undo		*undo;	 /* undo structure */
>  	int    			pid;	 /* process id of requesting process */
>  	int    			status;	 /* completion status of operation */
> -	struct sembuf *		sops;	 /* array of pending operations */
> +	struct sembuf		*sops;	 /* array of pending operations */
>  	int			nsops;	 /* number of operations */
>  	int			alter;   /* does the operation alter the array? */
>  };
> diff --git a/ipc/sem.c b/ipc/sem.c
> index 8cd96f1..38996c0 100644
> --- a/ipc/sem.c
> +++ b/ipc/sem.c
> @@ -272,8 +272,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
>  	ns->used_sems += nsems;
>  
>  	sma->sem_base = (struct sem *) &sma[1];
> -	/* sma->sem_pending = NULL; */
> -	sma->sem_pending_last = &sma->sem_pending;
> +	INIT_LIST_HEAD(&sma->sem_pending);
>  	INIT_LIST_HEAD(&sma->list_id);
>  	sma->sem_nsems = nsems;
>  	sma->sem_ctime = get_seconds();
> @@ -331,38 +330,6 @@ asmlinkage long sys_semget(key_t key, int nsems, int semflg)
>  	return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params);
>  }
>  
> -/* Manage the doubly linked list sma->sem_pending as a FIFO:
> - * insert new queue elements at the tail sma->sem_pending_last.
> - */
> -static inline void append_to_queue (struct sem_array * sma,
> -				    struct sem_queue * q)
> -{
> -	*(q->prev = sma->sem_pending_last) = q;
> -	*(sma->sem_pending_last = &q->next) = NULL;
> -}
> -
> -static inline void prepend_to_queue (struct sem_array * sma,
> -				     struct sem_queue * q)
> -{
> -	q->next = sma->sem_pending;
> -	*(q->prev = &sma->sem_pending) = q;
> -	if (q->next)
> -		q->next->prev = &q->next;
> -	else /* sma->sem_pending_last == &sma->sem_pending */
> -		sma->sem_pending_last = &q->next;
> -}
> -
> -static inline void remove_from_queue (struct sem_array * sma,
> -				      struct sem_queue * q)
> -{
> -	*(q->prev) = q->next;
> -	if (q->next)
> -		q->next->prev = q->prev;
> -	else /* sma->sem_pending_last == &q->next */
> -		sma->sem_pending_last = q->prev;
> -	q->prev = NULL; /* mark as removed */
> -}
> -
>  /*
>   * Determine whether a sequence of semaphore operations would succeed
>   * all at once. Return 0 if yes, 1 if need to sleep, else return error code.
> @@ -438,16 +405,15 @@ static void update_queue (struct sem_array * sma)
>  	int error;
>  	struct sem_queue * q;
>  
> -	q = sma->sem_pending;
> -	while(q) {
> +	q = list_entry(sma->sem_pending.next, struct sem_queue, list);
> +	while(&q->list != &sma->sem_pending) {

I guess here you are not using list_first_entry() because the pending 
requests might be empty?

>  		error = try_atomic_semop(sma, q->sops, q->nsops,
>  					 q->undo, q->pid);
>  
>  		/* Does q->sleeper still need to sleep? */
>  		if (error <= 0) {
>  			struct sem_queue *n;
> -			remove_from_queue(sma,q);
> -			q->status = IN_WAKEUP;
> +
>  			/*
>  			 * Continue scanning. The next operation
>  			 * that must be checked depends on the type of the
> @@ -458,11 +424,24 @@ static void update_queue (struct sem_array * sma)
>  			 *   for semaphore values to become 0.
>  			 * - if the operation didn't modify the array,
>  			 *   then just continue.
> +			 * The order of list_del() and reading ->next
> +			 * is crucial: In the former case, the list_del()
> +			 * must be done first [because we might be the
> +			 * first entry in ->sem_pending], in the latter
> +			 * case the list_del() must be done last
> +			 * [because the list is invalid after the list_del()]
>  			 */
> -			if (q->alter)
> -				n = sma->sem_pending;
> -			else
> -				n = q->next;
> +			if (q->alter) {
> +				list_del(&q->list);
> +				n = list_entry(sma->sem_pending.next, struct sem_queue, list);
> +			} else {
> +				n = list_entry(q->list.next, struct sem_queue, list);
> +				list_del(&q->list);
> +			}
> +
> +			/* wake up the waiting thread */
> +			q->status = IN_WAKEUP;
> +
>  			wake_up_process(q->sleeper);
>  			/* hands-off: q will disappear immediately after
>  			 * writing q->status.
> @@ -471,7 +450,7 @@ static void update_queue (struct sem_array * sma)
>  			q->status = error;
>  			q = n;
>  		} else {
> -			q = q->next;
> +			q = list_entry(q->list.next, struct sem_queue, list);
>  		}
>  	}
>  }
> @@ -491,7 +470,7 @@ static int count_semncnt (struct sem_array * sma, ushort semnum)
>  	struct sem_queue * q;
>  
>  	semncnt = 0;
> -	for (q = sma->sem_pending; q; q = q->next) {
> +	list_for_each_entry(q, &sma->sem_pending, list) {
>  		struct sembuf * sops = q->sops;
>  		int nsops = q->nsops;
>  		int i;
> @@ -503,13 +482,14 @@ static int count_semncnt (struct sem_array * sma, ushort semnum)
>  	}
>  	return semncnt;
>  }
> +
>  static int count_semzcnt (struct sem_array * sma, ushort semnum)
>  {
>  	int semzcnt;
>  	struct sem_queue * q;
>  
>  	semzcnt = 0;
> -	for (q = sma->sem_pending; q; q = q->next) {
> +	list_for_each_entry(q, &sma->sem_pending, list) {
>  		struct sembuf * sops = q->sops;
>  		int nsops = q->nsops;
>  		int i;
> @@ -529,7 +509,7 @@ static int count_semzcnt (struct sem_array * sma, ushort semnum)
>  static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
>  {
>  	struct sem_undo *un;
> -	struct sem_queue *q;
> +	struct sem_queue *q, *t;
>  	struct sem_array *sma = container_of(ipcp, struct sem_array, sem_perm);
>  
>  	/* Invalidate the existing undo structures for this semaphore set.
> @@ -541,17 +521,14 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
>  		un->semid = -1;
>  
>  	/* Wake up all pending processes and let them fail with EIDRM. */
> -	q = sma->sem_pending;
> -	while(q) {
> -		struct sem_queue *n;
> -		/* lazy remove_from_queue: we are killing the whole queue */
> -		q->prev = NULL;
> -		n = q->next;
> +
> +	list_for_each_entry_safe(q, t, &sma->sem_pending, list) {
> +		list_del(&q->list);
> +
>  		q->status = IN_WAKEUP;
>  		wake_up_process(q->sleeper); /* doesn't sleep */
>  		smp_wmb();
>  		q->status = -EIDRM;	/* hands-off q */
> -		q = n;
>  	}
>  
>  	/* Remove the semaphore set from the IDR */
> @@ -1166,9 +1143,9 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops,
>  	queue.pid = task_tgid_vnr(current);
>  	queue.alter = alter;
>  	if (alter)
> -		append_to_queue(sma ,&queue);
> +		list_add_tail(&queue.list, &sma->sem_pending);
>  	else
> -		prepend_to_queue(sma ,&queue);
> +		list_add(&queue.list, &sma->sem_pending);
>  
>  	queue.status = -EINTR;
>  	queue.sleeper = current;
> @@ -1194,7 +1171,6 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops,
>  
>  	sma = sem_lock(ns, semid);
>  	if (IS_ERR(sma)) {
> -		BUG_ON(queue.prev != NULL);

Instead of removing it why not replacing the bug_ON() by a check on the 
queue still being linked?

>  		error = -EIDRM;
>  		goto out_free;
>  	}
> @@ -1212,7 +1188,7 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops,
>  	 */
>  	if (timeout && jiffies_left == 0)
>  		error = -EAGAIN;
> -	remove_from_queue(sma,&queue);
> +	list_del(&queue.list);
>  	goto out_unlock_free;
>  
>  out_unlock_free:

Will have a look at the last patch + do some tests tomorrow.

Regards,
Nadia


  reply	other threads:[~2008-05-29 15:07 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-05-24 11:26 [PATCH 3/4] ipc/sem.c: convert sem_array.sem_pending to struct list_head Manfred Spraul
2008-05-29 15:06 ` Nadia Derbey [this message]
2008-06-07 14:52   ` Manfred Spraul

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=483EC693.7030808@bull.net \
    --to=nadia.derbey@bull.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=manfred@colorfullife.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.