[CRIU] [PATCH v4 14/33] files: Implement {set, wait}_fds_event()

Pavel Emelyanov xemul at virtuozzo.com
Tue Dec 20 07:45:50 PST 2016


On 12/13/2016 06:06 PM, Kirill Tkhai wrote:
> The idea is symilar to kernel's wake_up() and wait_event().
> One task needs some event. It checks the event has not
> happened yet (fle hasn't received, unix peer hasn't bound, etc)
> and calls get_fds_event(). Other task makes the event
> (sends a fle, binds the peer to a name, etc) and calls set_fds_event().
> 
> So, while there is no an event, the first task is sleeping,
> and the second wakes it up later:
> 
> Task A:      if (!socket_bound)
>                      wait_fds_event(); /* sleep */
> 
> Task B:      bind_socket();
>              set_fds_event();         /* wake up */

What if we have 3 tasks: A, waiting for B and, later, C.

A /* wait socket 1 */   B                                        C
  wait_fds_event
                          prepare_socket(1)
                          set_fds_event(A)
                                 cmpxchg(A->st, 0, FDS_EVENT)
                                 wake_up(A)
                                                                   prepare_socket(2)
                                                                   set_fds_event(A)
                                                                             if (A->st & FDS_EVENT)
                                                                                       wake_up(A)
  /* woken up */
  cmpxchg(st, FDS_EVENT, 0)
  /* restore socket 1 */
  /* wait socket 2 */
  wait_for_fds_event        <<<<<< never wakes up
  
> 
> v2: Do not wait for foreign transport sock is ready,
> as it's guarantied by we create it before CR_STATE_FORKING
> 
> Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
> ---
>  criu/files.c          |   34 ++++++++++++++++++++++++++++++++++
>  criu/include/files.h  |    2 ++
>  include/common/lock.h |    5 +++++
>  3 files changed, 41 insertions(+)
> 
> diff --git a/criu/files.c b/criu/files.c
> index 4039803..69a43c6 100644
> --- a/criu/files.c
> +++ b/criu/files.c
> @@ -1631,3 +1631,37 @@ int open_transport_socket(void)
>  
>  	return 0;
>  }
> +
> +int set_fds_event(pid_t virt)
> +{
> +	struct pstree_item *item;
> +	int old, st;
> +
> +	item = pstree_item_by_virt(virt);
> +	BUG_ON(!item);
> +
> +	/* Set FDS_EVENT and wake up if need */
> +	do {
> +		old = futex_get(&item->task_st);
> +		if (old & FDS_EVENT)
> +			break;
> +		st = atomic_cmpxchg(&item->task_st.raw, old, old | FDS_EVENT);
> +	} while (st != old);
> +
> +	if (!(old & FDS_EVENT))
> +		futex_wake(&item->task_st);
> +	return 0;
> +}
> +
> +int wait_fds_event(void)
> +{
> +	int old, st;
> +
> +	futex_wait_if_cond(&current->task_st, FDS_EVENT, &);
> +	do {
> +		old = futex_get(&current->task_st);
> +		st = atomic_cmpxchg(&current->task_st.raw, old, old & ~FDS_EVENT);
> +	} while (st != old);
> +
> +	return 0;
> +}
> diff --git a/criu/include/files.h b/criu/include/files.h
> index 5719004..7fdb3cf 100644
> --- a/criu/include/files.h
> +++ b/criu/include/files.h
> @@ -193,5 +193,7 @@ int dup_fle(struct pstree_item *task, struct fdinfo_list_entry *ple,
>  	    int fd, unsigned flags);
>  
>  extern int open_transport_socket(void);
> +extern int set_fds_event(pid_t virt);
> +extern int wait_fds_event(void);
>  
>  #endif /* __CR_FILES_H__ */
> diff --git a/include/common/lock.h b/include/common/lock.h
> index afc0f96..2261cf9 100644
> --- a/include/common/lock.h
> +++ b/include/common/lock.h
> @@ -78,6 +78,11 @@ static inline void futex_set_and_wake(futex_t *f, uint32_t v)
>  	LOCK_BUG_ON(sys_futex((uint32_t *)&f->raw.counter, FUTEX_WAKE, INT_MAX, NULL, NULL, 0) < 0);
>  }
>  
> +static inline void futex_wake(futex_t *f)
> +{
> +	LOCK_BUG_ON(sys_futex((uint32_t *)&f->raw.counter, FUTEX_WAKE, INT_MAX, NULL, NULL, 0) < 0);
> +}
> +
>  /* Mark futex @f as wait abort needed and wake up all waiters */
>  static inline void futex_abort_and_wake(futex_t *f)
>  {
> 
> .
> 



More information about the CRIU mailing list