diff mbox series

[RFC,v5,2/7] ui/vnc.c: polish vnc_init_func

Message ID 20181010120841.13214-3-fli@suse.com
State New
Headers show
Series qemu_thread_create: propagate errors to callers to check | expand

Commit Message

Fei Li Oct. 10, 2018, 12:08 p.m. UTC
Add a new Error parameter for vnc_display_init() to handle errors
in its caller: vnc_init_func(), just like vnc_display_open() does.
And let the call trace propagate the Error.

Besides, make vnc_start_worker_thread() return a bool to indicate
whether it succeeds instead of returning nothing.

Signed-off-by: Fei Li <fli@suse.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
---
 include/ui/console.h |  2 +-
 ui/vnc-jobs.c        |  9 ++++++---
 ui/vnc-jobs.h        |  2 +-
 ui/vnc.c             | 12 +++++++++---
 4 files changed, 17 insertions(+), 8 deletions(-)

Comments

Markus Armbruster Oct. 11, 2018, 1:13 p.m. UTC | #1
Fei Li <fli@suse.com> writes:

> Add a new Error parameter for vnc_display_init() to handle errors
> in its caller: vnc_init_func(), just like vnc_display_open() does.
> And let the call trace propagate the Error.
>
> Besides, make vnc_start_worker_thread() return a bool to indicate
> whether it succeeds instead of returning nothing.
>
> Signed-off-by: Fei Li <fli@suse.com>
> Reviewed-by: Fam Zheng <famz@redhat.com>
> ---
>  include/ui/console.h |  2 +-
>  ui/vnc-jobs.c        |  9 ++++++---
>  ui/vnc-jobs.h        |  2 +-
>  ui/vnc.c             | 12 +++++++++---
>  4 files changed, 17 insertions(+), 8 deletions(-)
>
> diff --git a/include/ui/console.h b/include/ui/console.h
> index fb969caf70..c17803c530 100644
> --- a/include/ui/console.h
> +++ b/include/ui/console.h
> @@ -453,7 +453,7 @@ void qemu_display_early_init(DisplayOptions *opts);
>  void qemu_display_init(DisplayState *ds, DisplayOptions *opts);
>  
>  /* vnc.c */
> -void vnc_display_init(const char *id);
> +void vnc_display_init(const char *id, Error **errp);
>  void vnc_display_open(const char *id, Error **errp);
>  void vnc_display_add_client(const char *id, int csock, bool skipauth);
>  int vnc_display_password(const char *id, const char *password);
> diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
> index 929391f85d..8807d7217c 100644
> --- a/ui/vnc-jobs.c
> +++ b/ui/vnc-jobs.c
> @@ -331,15 +331,18 @@ static bool vnc_worker_thread_running(void)
>      return queue; /* Check global queue */
>  }
>  
> -void vnc_start_worker_thread(void)
> +bool vnc_start_worker_thread(Error **errp)
>  {
>      VncJobQueue *q;
>  
> -    if (vnc_worker_thread_running())
> -        return ;
> +    if (vnc_worker_thread_running()) {
> +        goto out;
> +    }
>  
>      q = vnc_queue_init();
>      qemu_thread_create(&q->thread, "vnc_worker", vnc_worker_thread, q,
>                         QEMU_THREAD_DETACHED);
>      queue = q; /* Set global queue */
> +out:
> +    return true;
>  }

This function cannot fail.  Why convert it to Error, and complicate its
caller?

> diff --git a/ui/vnc-jobs.h b/ui/vnc-jobs.h
> index 59f66bcc35..14640593db 100644
> --- a/ui/vnc-jobs.h
> +++ b/ui/vnc-jobs.h
> @@ -37,7 +37,7 @@ void vnc_job_push(VncJob *job);
>  void vnc_jobs_join(VncState *vs);
>  
>  void vnc_jobs_consume_buffer(VncState *vs);
> -void vnc_start_worker_thread(void);
> +bool vnc_start_worker_thread(Error **errp);
>  
>  /* Locks */
>  static inline int vnc_trylock_display(VncDisplay *vd)
> diff --git a/ui/vnc.c b/ui/vnc.c
> index cf221c83cc..f3806e76db 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -3205,7 +3205,7 @@ static const DisplayChangeListenerOps dcl_ops = {
>      .dpy_cursor_define    = vnc_dpy_cursor_define,
>  };
>  
> -void vnc_display_init(const char *id)
> +void vnc_display_init(const char *id, Error **errp)
>  {
>      VncDisplay *vd;
>  
       if (vnc_display_find(id) != NULL) {
           return;
       }
       vd = g_malloc0(sizeof(*vd));

       vd->id = strdup(id);
       QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);

       QTAILQ_INIT(&vd->clients);
       vd->expires = TIME_MAX;

       if (keyboard_layout) {
           trace_vnc_key_map_init(keyboard_layout);
           vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
       } else {
           vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
       }

       if (!vd->kbd_layout) {
           exit(1);

Uh, init_keyboard_layout() reports errors to stderr, and the exit(1)
here makes them fatal.  Okay before this patch, but inappropriate
afterwards.  I'm afraid you have to convert init_keyboard_layout() to
Error first.

       }

       vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
> @@ -3235,7 +3235,9 @@ void vnc_display_init(const char *id)
>      vd->connections_limit = 32;
>  
>      qemu_mutex_init(&vd->mutex);
> -    vnc_start_worker_thread();
> +    if (!vnc_start_worker_thread(errp)) {
> +        return;
> +    }
>  
>      vd->dcl.ops = &dcl_ops;
>      register_displaychangelistener(&vd->dcl);
> @@ -4079,7 +4081,11 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
>      char *id = (char *)qemu_opts_id(opts);
>  
>      assert(id);
> -    vnc_display_init(id);
> +    vnc_display_init(id, &local_err);
> +    if (local_err) {
> +        error_reportf_err(local_err, "Failed to init VNC server: ");
> +        exit(1);
> +    }
>      vnc_display_open(id, &local_err);
>      if (local_err != NULL) {
>          error_reportf_err(local_err, "Failed to start VNC server: ");

Conflicts with my "[PATCH 24/31] vl: Clean up error reporting in
vnc_init_func()".  Your patch shows that mine is incomplete.

Without my patch, there's no real reason for yours, however.  The two
should be squashed together.
Fei Li Oct. 12, 2018, 5:40 a.m. UTC | #2
On 10/11/2018 09:13 PM, Markus Armbruster wrote:
> Fei Li <fli@suse.com> writes:
>
>> Add a new Error parameter for vnc_display_init() to handle errors
>> in its caller: vnc_init_func(), just like vnc_display_open() does.
>> And let the call trace propagate the Error.
>>
>> Besides, make vnc_start_worker_thread() return a bool to indicate
>> whether it succeeds instead of returning nothing.
>>
>> Signed-off-by: Fei Li <fli@suse.com>
>> Reviewed-by: Fam Zheng <famz@redhat.com>
>> ---
>>   include/ui/console.h |  2 +-
>>   ui/vnc-jobs.c        |  9 ++++++---
>>   ui/vnc-jobs.h        |  2 +-
>>   ui/vnc.c             | 12 +++++++++---
>>   4 files changed, 17 insertions(+), 8 deletions(-)
>>
>> diff --git a/include/ui/console.h b/include/ui/console.h
>> index fb969caf70..c17803c530 100644
>> --- a/include/ui/console.h
>> +++ b/include/ui/console.h
>> @@ -453,7 +453,7 @@ void qemu_display_early_init(DisplayOptions *opts);
>>   void qemu_display_init(DisplayState *ds, DisplayOptions *opts);
>>   
>>   /* vnc.c */
>> -void vnc_display_init(const char *id);
>> +void vnc_display_init(const char *id, Error **errp);
>>   void vnc_display_open(const char *id, Error **errp);
>>   void vnc_display_add_client(const char *id, int csock, bool skipauth);
>>   int vnc_display_password(const char *id, const char *password);
>> diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
>> index 929391f85d..8807d7217c 100644
>> --- a/ui/vnc-jobs.c
>> +++ b/ui/vnc-jobs.c
>> @@ -331,15 +331,18 @@ static bool vnc_worker_thread_running(void)
>>       return queue; /* Check global queue */
>>   }
>>   
>> -void vnc_start_worker_thread(void)
>> +bool vnc_start_worker_thread(Error **errp)
>>   {
>>       VncJobQueue *q;
>>   
>> -    if (vnc_worker_thread_running())
>> -        return ;
>> +    if (vnc_worker_thread_running()) {
>> +        goto out;
>> +    }
>>   
>>       q = vnc_queue_init();
>>       qemu_thread_create(&q->thread, "vnc_worker", vnc_worker_thread, q,
>>                          QEMU_THREAD_DETACHED);
>>       queue = q; /* Set global queue */
>> +out:
>> +    return true;
>>   }
> This function cannot fail.  Why convert it to Error, and complicate its
> caller?
[Issue1]
Actually, this is to pave the way for patch 7/7, in case 
qemu_thread_create() fails.
Patch 7/7 is long enough, thus I wrote the patch 1/2/3 separately to mainly
connects the broken errp for callers who initially have the errp.

[I am back... If the other codes in this patches be squashed, maybe 
merge [Issue1]
into patch 7/7 looks more intuitive.]
>> diff --git a/ui/vnc-jobs.h b/ui/vnc-jobs.h
>> index 59f66bcc35..14640593db 100644
>> --- a/ui/vnc-jobs.h
>> +++ b/ui/vnc-jobs.h
>> @@ -37,7 +37,7 @@ void vnc_job_push(VncJob *job);
>>   void vnc_jobs_join(VncState *vs);
>>   
>>   void vnc_jobs_consume_buffer(VncState *vs);
>> -void vnc_start_worker_thread(void);
>> +bool vnc_start_worker_thread(Error **errp);
>>   
>>   /* Locks */
>>   static inline int vnc_trylock_display(VncDisplay *vd)
>> diff --git a/ui/vnc.c b/ui/vnc.c
>> index cf221c83cc..f3806e76db 100644
>> --- a/ui/vnc.c
>> +++ b/ui/vnc.c
>> @@ -3205,7 +3205,7 @@ static const DisplayChangeListenerOps dcl_ops = {
>>       .dpy_cursor_define    = vnc_dpy_cursor_define,
>>   };
>>   
>> -void vnc_display_init(const char *id)
>> +void vnc_display_init(const char *id, Error **errp)
>>   {
>>       VncDisplay *vd;
>>   
>         if (vnc_display_find(id) != NULL) {
>             return;
>         }
>         vd = g_malloc0(sizeof(*vd));
>
>         vd->id = strdup(id);
>         QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
>
>         QTAILQ_INIT(&vd->clients);
>         vd->expires = TIME_MAX;
>
>         if (keyboard_layout) {
>             trace_vnc_key_map_init(keyboard_layout);
>             vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
>         } else {
>             vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
>         }
>
>         if (!vd->kbd_layout) {
>             exit(1);
>
> Uh, init_keyboard_layout() reports errors to stderr, and the exit(1)
> here makes them fatal.  Okay before this patch, but inappropriate
> afterwards.  I'm afraid you have to convert init_keyboard_layout() to
> Error first.
[Issue2]
Right. But I notice the returned kbd_layout_t *kbd_layout is a static 
value and also
will be used by others, how about passing the errp parameter to 
init_keyboard_layout()
as follows? And for its other callers, just pass NULL.

@@ -3222,13 +3222,13 @@ void vnc_display_init(const char *id, Error **errp)

      if (keyboard_layout) {
          trace_vnc_key_map_init(keyboard_layout);
-        vd->kbd_layout = init_keyboard_layout(name2keysym, 
keyboard_layout);
+        vd->kbd_layout = init_keyboard_layout(name2keysym, 
keyboard_layout, errp);
      } else {
-        vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
+        vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us", errp);
      }

      if (!vd->kbd_layout) {
-        exit(1);
+        return;
      }

>
>         }
>
>         vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
>> @@ -3235,7 +3235,9 @@ void vnc_display_init(const char *id)
>>       vd->connections_limit = 32;
>>   
>>       qemu_mutex_init(&vd->mutex);
>> -    vnc_start_worker_thread();
>> +    if (!vnc_start_worker_thread(errp)) {
>> +        return;
>> +    }
>>   
>>       vd->dcl.ops = &dcl_ops;
>>       register_displaychangelistener(&vd->dcl);
>> @@ -4079,7 +4081,11 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
>>       char *id = (char *)qemu_opts_id(opts);
>>   
>>       assert(id);
>> -    vnc_display_init(id);
>> +    vnc_display_init(id, &local_err);
>> +    if (local_err) {
>> +        error_reportf_err(local_err, "Failed to init VNC server: ");
>> +        exit(1);
>> +    }
>>       vnc_display_open(id, &local_err);
>>       if (local_err != NULL) {
>>           error_reportf_err(local_err, "Failed to start VNC server: ");
> Conflicts with my "[PATCH 24/31] vl: Clean up error reporting in
> vnc_init_func()".  Your patch shows that mine is incomplete.
>
> Without my patch, there's no real reason for yours, however.  The two
> should be squashed together.
Ah, I noticed your patch 24/31. OK, let's squash.
Should I write a new patch by
- updating to error_propagate(...) if vnc_display_init() fails
&&
- modifying [Issue2] ?
Or you do this in your original patch?

BTW, for your patch 24/31, the updated passed errp for vnc_init_func is 
&error_fatal,
then the system will exit(1) when running error_propagate(...) which calls
error_handle_fatal(...). This means the following two lines will not be 
touched.
But if we want the following prepended error message, could we move it 
earlier than
the error_propagare? I mean:

      if (local_err != NULL) {
-        error_reportf_err(local_err, "Failed to start VNC server: ");
-        exit(1);
+        error_prepend(&local_err, "Failed to start VNC server: ");
+        error_propagate(errp, local_err);
+        return -1;
      }

Have a nice day
Fei
Markus Armbruster Oct. 12, 2018, 8:18 a.m. UTC | #3
Fei Li <fli@suse.com> writes:

> On 10/11/2018 09:13 PM, Markus Armbruster wrote:
>> Fei Li <fli@suse.com> writes:
>>
>>> Add a new Error parameter for vnc_display_init() to handle errors
>>> in its caller: vnc_init_func(), just like vnc_display_open() does.
>>> And let the call trace propagate the Error.
>>>
>>> Besides, make vnc_start_worker_thread() return a bool to indicate
>>> whether it succeeds instead of returning nothing.
>>>
>>> Signed-off-by: Fei Li <fli@suse.com>
>>> Reviewed-by: Fam Zheng <famz@redhat.com>
>>> ---
>>>   include/ui/console.h |  2 +-
>>>   ui/vnc-jobs.c        |  9 ++++++---
>>>   ui/vnc-jobs.h        |  2 +-
>>>   ui/vnc.c             | 12 +++++++++---
>>>   4 files changed, 17 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/include/ui/console.h b/include/ui/console.h
>>> index fb969caf70..c17803c530 100644
>>> --- a/include/ui/console.h
>>> +++ b/include/ui/console.h
>>> @@ -453,7 +453,7 @@ void qemu_display_early_init(DisplayOptions *opts);
>>>   void qemu_display_init(DisplayState *ds, DisplayOptions *opts);
>>>     /* vnc.c */
>>> -void vnc_display_init(const char *id);
>>> +void vnc_display_init(const char *id, Error **errp);
>>>   void vnc_display_open(const char *id, Error **errp);
>>>   void vnc_display_add_client(const char *id, int csock, bool skipauth);
>>>   int vnc_display_password(const char *id, const char *password);
>>> diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
>>> index 929391f85d..8807d7217c 100644
>>> --- a/ui/vnc-jobs.c
>>> +++ b/ui/vnc-jobs.c
>>> @@ -331,15 +331,18 @@ static bool vnc_worker_thread_running(void)
>>>       return queue; /* Check global queue */
>>>   }
>>>   -void vnc_start_worker_thread(void)
>>> +bool vnc_start_worker_thread(Error **errp)
>>>   {
>>>       VncJobQueue *q;
>>>   -    if (vnc_worker_thread_running())
>>> -        return ;
>>> +    if (vnc_worker_thread_running()) {
>>> +        goto out;
>>> +    }
>>>         q = vnc_queue_init();
>>>       qemu_thread_create(&q->thread, "vnc_worker", vnc_worker_thread, q,
>>>                          QEMU_THREAD_DETACHED);
>>>       queue = q; /* Set global queue */
>>> +out:
>>> +    return true;
>>>   }
>> This function cannot fail.  Why convert it to Error, and complicate its
>> caller?
> [Issue1]
> Actually, this is to pave the way for patch 7/7, in case
> qemu_thread_create() fails.
> Patch 7/7 is long enough, thus I wrote the patch 1/2/3 separately to mainly
> connects the broken errp for callers who initially have the errp.
>
> [I am back... If the other codes in this patches be squashed, maybe
> merge [Issue1]
> into patch 7/7 looks more intuitive.]
>>> diff --git a/ui/vnc-jobs.h b/ui/vnc-jobs.h
>>> index 59f66bcc35..14640593db 100644
>>> --- a/ui/vnc-jobs.h
>>> +++ b/ui/vnc-jobs.h
>>> @@ -37,7 +37,7 @@ void vnc_job_push(VncJob *job);
>>>   void vnc_jobs_join(VncState *vs);
>>>     void vnc_jobs_consume_buffer(VncState *vs);
>>> -void vnc_start_worker_thread(void);
>>> +bool vnc_start_worker_thread(Error **errp);
>>>     /* Locks */
>>>   static inline int vnc_trylock_display(VncDisplay *vd)
>>> diff --git a/ui/vnc.c b/ui/vnc.c
>>> index cf221c83cc..f3806e76db 100644
>>> --- a/ui/vnc.c
>>> +++ b/ui/vnc.c
>>> @@ -3205,7 +3205,7 @@ static const DisplayChangeListenerOps dcl_ops = {
>>>       .dpy_cursor_define    = vnc_dpy_cursor_define,
>>>   };
>>>   -void vnc_display_init(const char *id)
>>> +void vnc_display_init(const char *id, Error **errp)
>>>   {
>>>       VncDisplay *vd;
>>>   
>>         if (vnc_display_find(id) != NULL) {
>>             return;
>>         }
>>         vd = g_malloc0(sizeof(*vd));
>>
>>         vd->id = strdup(id);
>>         QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
>>
>>         QTAILQ_INIT(&vd->clients);
>>         vd->expires = TIME_MAX;
>>
>>         if (keyboard_layout) {
>>             trace_vnc_key_map_init(keyboard_layout);
>>             vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
>>         } else {
>>             vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
>>         }
>>
>>         if (!vd->kbd_layout) {
>>             exit(1);
>>
>> Uh, init_keyboard_layout() reports errors to stderr, and the exit(1)
>> here makes them fatal.  Okay before this patch, but inappropriate
>> afterwards.  I'm afraid you have to convert init_keyboard_layout() to
>> Error first.
> [Issue2]
> Right. But I notice the returned kbd_layout_t *kbd_layout is a static
> value and also
> will be used by others, how about passing the errp parameter to
> init_keyboard_layout()
> as follows? And for its other callers, just pass NULL.
>
> @@ -3222,13 +3222,13 @@ void vnc_display_init(const char *id, Error **errp)
>
>      if (keyboard_layout) {
>          trace_vnc_key_map_init(keyboard_layout);
> -        vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
> +        vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout, errp);
>      } else {
> -        vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
> +        vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us", errp);
>      }
>
>      if (!vd->kbd_layout) {
> -        exit(1);
> +        return;
>      }

Sounds good to me, except you should pass &error_fatal instead of NULL
to preserve "report error and exit" semantics.

>>
>>         }
>>
>>         vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
>>> @@ -3235,7 +3235,9 @@ void vnc_display_init(const char *id)
>>>       vd->connections_limit = 32;
>>>         qemu_mutex_init(&vd->mutex);
>>> -    vnc_start_worker_thread();
>>> +    if (!vnc_start_worker_thread(errp)) {
>>> +        return;
>>> +    }
>>>         vd->dcl.ops = &dcl_ops;
>>>       register_displaychangelistener(&vd->dcl);
>>> @@ -4079,7 +4081,11 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
>>>       char *id = (char *)qemu_opts_id(opts);
>>>         assert(id);
>>> -    vnc_display_init(id);
>>> +    vnc_display_init(id, &local_err);
>>> +    if (local_err) {
>>> +        error_reportf_err(local_err, "Failed to init VNC server: ");
>>> +        exit(1);
>>> +    }
>>>       vnc_display_open(id, &local_err);
>>>       if (local_err != NULL) {
>>>           error_reportf_err(local_err, "Failed to start VNC server: ");
>> Conflicts with my "[PATCH 24/31] vl: Clean up error reporting in
>> vnc_init_func()".  Your patch shows that mine is incomplete.
>>
>> Without my patch, there's no real reason for yours, however.  The two
>> should be squashed together.
> Ah, I noticed your patch 24/31. OK, let's squash.
> Should I write a new patch by
> - updating to error_propagate(...) if vnc_display_init() fails
> &&
> - modifying [Issue2] ?
> Or you do this in your original patch?

If you send a v2 along that lines, I'll probably pick your patch into my
series.  Should work even in case your series gets merged first.

> BTW, for your patch 24/31, the updated passed errp for vnc_init_func
> is &error_fatal,
> then the system will exit(1) when running error_propagate(...) which calls
> error_handle_fatal(...). This means the following two lines will not
> be touched.
> But if we want the following prepended error message, could we move it
> earlier than
> the error_propagare? I mean:
>
>      if (local_err != NULL) {
> -        error_reportf_err(local_err, "Failed to start VNC server: ");
> -        exit(1);
> +        error_prepend(&local_err, "Failed to start VNC server: ");
> +        error_propagate(errp, local_err);
> +        return -1;
>      }

Both

         error_propagate(errp, local_err);
         error_prepend(errp, "Failed to start VNC server: ");

and

        error_prepend(&local_err, "Failed to start VNC server: ");
        error_propagate(errp, local_err);

work.  The former is slightly more efficient when errp is null.  But
you're right, it fails to include the "Failed to start VNC server: "
prefix with &error_fatal.  Thus, the latter is preferrable.
Fei Li Oct. 12, 2018, 10:23 a.m. UTC | #4
On 10/12/2018 04:18 PM, Markus Armbruster wrote:
> Fei Li <fli@suse.com> writes:
>
>> On 10/11/2018 09:13 PM, Markus Armbruster wrote:
>>> Fei Li <fli@suse.com> writes:
>>>
>>>> Add a new Error parameter for vnc_display_init() to handle errors
>>>> in its caller: vnc_init_func(), just like vnc_display_open() does.
>>>> And let the call trace propagate the Error.
>>>>
>>>> Besides, make vnc_start_worker_thread() return a bool to indicate
>>>> whether it succeeds instead of returning nothing.
>>>>
>>>> Signed-off-by: Fei Li <fli@suse.com>
>>>> Reviewed-by: Fam Zheng <famz@redhat.com>
>>>> ---
>>>>    include/ui/console.h |  2 +-
>>>>    ui/vnc-jobs.c        |  9 ++++++---
>>>>    ui/vnc-jobs.h        |  2 +-
>>>>    ui/vnc.c             | 12 +++++++++---
>>>>    4 files changed, 17 insertions(+), 8 deletions(-)
>>>>
>>>> diff --git a/include/ui/console.h b/include/ui/console.h
>>>> index fb969caf70..c17803c530 100644
>>>> --- a/include/ui/console.h
>>>> +++ b/include/ui/console.h
>>>> @@ -453,7 +453,7 @@ void qemu_display_early_init(DisplayOptions *opts);
>>>>    void qemu_display_init(DisplayState *ds, DisplayOptions *opts);
>>>>      /* vnc.c */
>>>> -void vnc_display_init(const char *id);
>>>> +void vnc_display_init(const char *id, Error **errp);
>>>>    void vnc_display_open(const char *id, Error **errp);
>>>>    void vnc_display_add_client(const char *id, int csock, bool skipauth);
>>>>    int vnc_display_password(const char *id, const char *password);
>>>> diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
>>>> index 929391f85d..8807d7217c 100644
>>>> --- a/ui/vnc-jobs.c
>>>> +++ b/ui/vnc-jobs.c
>>>> @@ -331,15 +331,18 @@ static bool vnc_worker_thread_running(void)
>>>>        return queue; /* Check global queue */
>>>>    }
>>>>    -void vnc_start_worker_thread(void)
>>>> +bool vnc_start_worker_thread(Error **errp)
>>>>    {
>>>>        VncJobQueue *q;
>>>>    -    if (vnc_worker_thread_running())
>>>> -        return ;
>>>> +    if (vnc_worker_thread_running()) {
>>>> +        goto out;
>>>> +    }
>>>>          q = vnc_queue_init();
>>>>        qemu_thread_create(&q->thread, "vnc_worker", vnc_worker_thread, q,
>>>>                           QEMU_THREAD_DETACHED);
>>>>        queue = q; /* Set global queue */
>>>> +out:
>>>> +    return true;
>>>>    }
>>> This function cannot fail.  Why convert it to Error, and complicate its
>>> caller?
>> [Issue1]
>> Actually, this is to pave the way for patch 7/7, in case
>> qemu_thread_create() fails.
>> Patch 7/7 is long enough, thus I wrote the patch 1/2/3 separately to mainly
>> connects the broken errp for callers who initially have the errp.
>>
>> [I am back... If the other codes in this patches be squashed, maybe
>> merge [Issue1]
>> into patch 7/7 looks more intuitive.]
>>>> diff --git a/ui/vnc-jobs.h b/ui/vnc-jobs.h
>>>> index 59f66bcc35..14640593db 100644
>>>> --- a/ui/vnc-jobs.h
>>>> +++ b/ui/vnc-jobs.h
>>>> @@ -37,7 +37,7 @@ void vnc_job_push(VncJob *job);
>>>>    void vnc_jobs_join(VncState *vs);
>>>>      void vnc_jobs_consume_buffer(VncState *vs);
>>>> -void vnc_start_worker_thread(void);
>>>> +bool vnc_start_worker_thread(Error **errp);
>>>>      /* Locks */
>>>>    static inline int vnc_trylock_display(VncDisplay *vd)
>>>> diff --git a/ui/vnc.c b/ui/vnc.c
>>>> index cf221c83cc..f3806e76db 100644
>>>> --- a/ui/vnc.c
>>>> +++ b/ui/vnc.c
>>>> @@ -3205,7 +3205,7 @@ static const DisplayChangeListenerOps dcl_ops = {
>>>>        .dpy_cursor_define    = vnc_dpy_cursor_define,
>>>>    };
>>>>    -void vnc_display_init(const char *id)
>>>> +void vnc_display_init(const char *id, Error **errp)
>>>>    {
>>>>        VncDisplay *vd;
>>>>    
>>>          if (vnc_display_find(id) != NULL) {
>>>              return;
>>>          }
>>>          vd = g_malloc0(sizeof(*vd));
>>>
>>>          vd->id = strdup(id);
>>>          QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
>>>
>>>          QTAILQ_INIT(&vd->clients);
>>>          vd->expires = TIME_MAX;
>>>
>>>          if (keyboard_layout) {
>>>              trace_vnc_key_map_init(keyboard_layout);
>>>              vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
>>>          } else {
>>>              vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
>>>          }
>>>
>>>          if (!vd->kbd_layout) {
>>>              exit(1);
>>>
>>> Uh, init_keyboard_layout() reports errors to stderr, and the exit(1)
>>> here makes them fatal.  Okay before this patch, but inappropriate
>>> afterwards.  I'm afraid you have to convert init_keyboard_layout() to
>>> Error first.
>> [Issue2]
>> Right. But I notice the returned kbd_layout_t *kbd_layout is a static
>> value and also
>> will be used by others, how about passing the errp parameter to
>> init_keyboard_layout()
>> as follows? And for its other callers, just pass NULL.
>>
>> @@ -3222,13 +3222,13 @@ void vnc_display_init(const char *id, Error **errp)
>>
>>       if (keyboard_layout) {
>>           trace_vnc_key_map_init(keyboard_layout);
>> -        vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
>> +        vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout, errp);
>>       } else {
>> -        vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
>> +        vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us", errp);
>>       }
>>
>>       if (!vd->kbd_layout) {
>> -        exit(1);
>> +        return;
>>       }
> Sounds good to me, except you should pass &error_fatal instead of NULL
> to preserve "report error and exit" semantics.
Yes, you are right. I should pass &error_fatal and let the following 
error_setg() handle this.

@@ -94,7 +94,7 @@ static kbd_layout_t *parse_keyboard_layout(const 
name2keysym_t *table,
      f = filename ? fopen(filename, "r") : NULL;
      g_free(filename);
      if (!f) {
-        fprintf(stderr, "Could not read keymap file: '%s'\n", language);
+        error_setg(errp, "could not read keymap file: '%s'\n", language);
          return NULL;
      }

>
>>>          }
>>>
>>>          vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
>>>> @@ -3235,7 +3235,9 @@ void vnc_display_init(const char *id)
>>>>        vd->connections_limit = 32;
>>>>          qemu_mutex_init(&vd->mutex);
>>>> -    vnc_start_worker_thread();
>>>> +    if (!vnc_start_worker_thread(errp)) {
>>>> +        return;
>>>> +    }
>>>>          vd->dcl.ops = &dcl_ops;
>>>>        register_displaychangelistener(&vd->dcl);
>>>> @@ -4079,7 +4081,11 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
>>>>        char *id = (char *)qemu_opts_id(opts);
>>>>          assert(id);
>>>> -    vnc_display_init(id);
>>>> +    vnc_display_init(id, &local_err);
>>>> +    if (local_err) {
>>>> +        error_reportf_err(local_err, "Failed to init VNC server: ");
>>>> +        exit(1);
>>>> +    }
>>>>        vnc_display_open(id, &local_err);
>>>>        if (local_err != NULL) {
>>>>            error_reportf_err(local_err, "Failed to start VNC server: ");
>>> Conflicts with my "[PATCH 24/31] vl: Clean up error reporting in
>>> vnc_init_func()".  Your patch shows that mine is incomplete.
>>>
>>> Without my patch, there's no real reason for yours, however.  The two
>>> should be squashed together.
>> Ah, I noticed your patch 24/31. OK, let's squash.
>> Should I write a new patch by
>> - updating to error_propagate(...) if vnc_display_init() fails
>> &&
>> - modifying [Issue2] ?
>> Or you do this in your original patch?
> If you send a v2 along that lines, I'll probably pick your patch into my
> series.  Should work even in case your series gets merged first.
Good idea. I will send a separate v2 patch which also include the
above change mentioned in [Issue1].
>
>> BTW, for your patch 24/31, the updated passed errp for vnc_init_func
>> is &error_fatal,
>> then the system will exit(1) when running error_propagate(...) which calls
>> error_handle_fatal(...). This means the following two lines will not
>> be touched.
>> But if we want the following prepended error message, could we move it
>> earlier than
>> the error_propagare? I mean:
>>
>>       if (local_err != NULL) {
>> -        error_reportf_err(local_err, "Failed to start VNC server: ");
>> -        exit(1);
>> +        error_prepend(&local_err, "Failed to start VNC server: ");
>> +        error_propagate(errp, local_err);
>> +        return -1;
>>       }
> Both
>
>           error_propagate(errp, local_err);
>           error_prepend(errp, "Failed to start VNC server: ");
>
> and
>
>          error_prepend(&local_err, "Failed to start VNC server: ");
>          error_propagate(errp, local_err);
>
> work.  The former is slightly more efficient when errp is null.  But
> you're right, it fails to include the "Failed to start VNC server: "
> prefix with &error_fatal.  Thus, the latter is preferrable.
>
>
Have a nice day, thanks
Fei
Fei Li Oct. 12, 2018, 10:50 a.m. UTC | #5
On 10/12/2018 06:23 PM, Fei Li wrote:
>
>
> On 10/12/2018 04:18 PM, Markus Armbruster wrote:
>> Fei Li <fli@suse.com> writes:
>>
>>> On 10/11/2018 09:13 PM, Markus Armbruster wrote:
>>>> Fei Li <fli@suse.com> writes:
>>>>
>>>>> Add a new Error parameter for vnc_display_init() to handle errors
>>>>> in its caller: vnc_init_func(), just like vnc_display_open() does.
>>>>> And let the call trace propagate the Error.
>>>>>
>>>>> Besides, make vnc_start_worker_thread() return a bool to indicate
>>>>> whether it succeeds instead of returning nothing.
>>>>>
>>>>> Signed-off-by: Fei Li <fli@suse.com>
>>>>> Reviewed-by: Fam Zheng <famz@redhat.com>
>>>>> ---
>>>>>    include/ui/console.h |  2 +-
>>>>>    ui/vnc-jobs.c        |  9 ++++++---
>>>>>    ui/vnc-jobs.h        |  2 +-
>>>>>    ui/vnc.c             | 12 +++++++++---
>>>>>    4 files changed, 17 insertions(+), 8 deletions(-)
>>>>>
>>>>> diff --git a/include/ui/console.h b/include/ui/console.h
>>>>> index fb969caf70..c17803c530 100644
>>>>> --- a/include/ui/console.h
>>>>> +++ b/include/ui/console.h
>>>>> @@ -453,7 +453,7 @@ void qemu_display_early_init(DisplayOptions 
>>>>> *opts);
>>>>>    void qemu_display_init(DisplayState *ds, DisplayOptions *opts);
>>>>>      /* vnc.c */
>>>>> -void vnc_display_init(const char *id);
>>>>> +void vnc_display_init(const char *id, Error **errp);
>>>>>    void vnc_display_open(const char *id, Error **errp);
>>>>>    void vnc_display_add_client(const char *id, int csock, bool 
>>>>> skipauth);
>>>>>    int vnc_display_password(const char *id, const char *password);
>>>>> diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
>>>>> index 929391f85d..8807d7217c 100644
>>>>> --- a/ui/vnc-jobs.c
>>>>> +++ b/ui/vnc-jobs.c
>>>>> @@ -331,15 +331,18 @@ static bool vnc_worker_thread_running(void)
>>>>>        return queue; /* Check global queue */
>>>>>    }
>>>>>    -void vnc_start_worker_thread(void)
>>>>> +bool vnc_start_worker_thread(Error **errp)
>>>>>    {
>>>>>        VncJobQueue *q;
>>>>>    -    if (vnc_worker_thread_running())
>>>>> -        return ;
>>>>> +    if (vnc_worker_thread_running()) {
>>>>> +        goto out;
>>>>> +    }
>>>>>          q = vnc_queue_init();
>>>>>        qemu_thread_create(&q->thread, "vnc_worker", 
>>>>> vnc_worker_thread, q,
>>>>>                           QEMU_THREAD_DETACHED);
>>>>>        queue = q; /* Set global queue */
>>>>> +out:
>>>>> +    return true;
>>>>>    }
>>>> This function cannot fail.  Why convert it to Error, and complicate 
>>>> its
>>>> caller?
>>> [Issue1]
>>> Actually, this is to pave the way for patch 7/7, in case
>>> qemu_thread_create() fails.
>>> Patch 7/7 is long enough, thus I wrote the patch 1/2/3 separately to 
>>> mainly
>>> connects the broken errp for callers who initially have the errp.
>>>
>>> [I am back... If the other codes in this patches be squashed, maybe
>>> merge [Issue1]
>>> into patch 7/7 looks more intuitive.]
>>>>> diff --git a/ui/vnc-jobs.h b/ui/vnc-jobs.h
>>>>> index 59f66bcc35..14640593db 100644
>>>>> --- a/ui/vnc-jobs.h
>>>>> +++ b/ui/vnc-jobs.h
>>>>> @@ -37,7 +37,7 @@ void vnc_job_push(VncJob *job);
>>>>>    void vnc_jobs_join(VncState *vs);
>>>>>      void vnc_jobs_consume_buffer(VncState *vs);
>>>>> -void vnc_start_worker_thread(void);
>>>>> +bool vnc_start_worker_thread(Error **errp);
>>>>>      /* Locks */
>>>>>    static inline int vnc_trylock_display(VncDisplay *vd)
>>>>> diff --git a/ui/vnc.c b/ui/vnc.c
>>>>> index cf221c83cc..f3806e76db 100644
>>>>> --- a/ui/vnc.c
>>>>> +++ b/ui/vnc.c
>>>>> @@ -3205,7 +3205,7 @@ static const DisplayChangeListenerOps 
>>>>> dcl_ops = {
>>>>>        .dpy_cursor_define    = vnc_dpy_cursor_define,
>>>>>    };
>>>>>    -void vnc_display_init(const char *id)
>>>>> +void vnc_display_init(const char *id, Error **errp)
>>>>>    {
>>>>>        VncDisplay *vd;
>>>>          if (vnc_display_find(id) != NULL) {
>>>>              return;
>>>>          }
>>>>          vd = g_malloc0(sizeof(*vd));
>>>>
>>>>          vd->id = strdup(id);
>>>>          QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
>>>>
>>>>          QTAILQ_INIT(&vd->clients);
>>>>          vd->expires = TIME_MAX;
>>>>
>>>>          if (keyboard_layout) {
>>>>              trace_vnc_key_map_init(keyboard_layout);
>>>>              vd->kbd_layout = init_keyboard_layout(name2keysym, 
>>>> keyboard_layout);
>>>>          } else {
>>>>              vd->kbd_layout = init_keyboard_layout(name2keysym, 
>>>> "en-us");
>>>>          }
>>>>
>>>>          if (!vd->kbd_layout) {
>>>>              exit(1);
>>>>
>>>> Uh, init_keyboard_layout() reports errors to stderr, and the exit(1)
>>>> here makes them fatal.  Okay before this patch, but inappropriate
>>>> afterwards.  I'm afraid you have to convert init_keyboard_layout() to
>>>> Error first.
>>> [Issue2]
>>> Right. But I notice the returned kbd_layout_t *kbd_layout is a static
>>> value and also
>>> will be used by others, how about passing the errp parameter to
>>> init_keyboard_layout()
>>> as follows? And for its other callers, just pass NULL.
>>>
>>> @@ -3222,13 +3222,13 @@ void vnc_display_init(const char *id, Error 
>>> **errp)
>>>
>>>       if (keyboard_layout) {
>>>           trace_vnc_key_map_init(keyboard_layout);
>>> -        vd->kbd_layout = init_keyboard_layout(name2keysym, 
>>> keyboard_layout);
>>> +        vd->kbd_layout = init_keyboard_layout(name2keysym, 
>>> keyboard_layout, errp);
>>>       } else {
>>> -        vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
>>> +        vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us", 
>>> errp);
>>>       }
>>>
>>>       if (!vd->kbd_layout) {
>>> -        exit(1);
>>> +        return;
>>>       }
>> Sounds good to me, except you should pass &error_fatal instead of NULL
>> to preserve "report error and exit" semantics.
> Yes, you are right. I should pass &error_fatal and let the following 
> error_setg() handle this.
>
> @@ -94,7 +94,7 @@ static kbd_layout_t *parse_keyboard_layout(const 
> name2keysym_t *table,
>      f = filename ? fopen(filename, "r") : NULL;
>      g_free(filename);
>      if (!f) {
> -        fprintf(stderr, "Could not read keymap file: '%s'\n", language);
> +        error_setg(errp, "could not read keymap file: '%s'\n", 
> language);
>          return NULL;
>      }
>
>>
>>>>          }
>>>>
>>>>          vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
>>>>> @@ -3235,7 +3235,9 @@ void vnc_display_init(const char *id)
>>>>>        vd->connections_limit = 32;
>>>>>          qemu_mutex_init(&vd->mutex);
>>>>> -    vnc_start_worker_thread();
>>>>> +    if (!vnc_start_worker_thread(errp)) {
>>>>> +        return;
>>>>> +    }
>>>>>          vd->dcl.ops = &dcl_ops;
>>>>>        register_displaychangelistener(&vd->dcl);
>>>>> @@ -4079,7 +4081,11 @@ int vnc_init_func(void *opaque, QemuOpts 
>>>>> *opts, Error **errp)
>>>>>        char *id = (char *)qemu_opts_id(opts);
>>>>>          assert(id);
>>>>> -    vnc_display_init(id);
>>>>> +    vnc_display_init(id, &local_err);
>>>>> +    if (local_err) {
>>>>> +        error_reportf_err(local_err, "Failed to init VNC server: ");
>>>>> +        exit(1);
>>>>> +    }
>>>>>        vnc_display_open(id, &local_err);
>>>>>        if (local_err != NULL) {
>>>>>            error_reportf_err(local_err, "Failed to start VNC 
>>>>> server: ");
>>>> Conflicts with my "[PATCH 24/31] vl: Clean up error reporting in
>>>> vnc_init_func()".  Your patch shows that mine is incomplete.
>>>>
>>>> Without my patch, there's no real reason for yours, however.  The two
>>>> should be squashed together.
>>> Ah, I noticed your patch 24/31. OK, let's squash.
>>> Should I write a new patch by
>>> - updating to error_propagate(...) if vnc_display_init() fails
>>> &&
>>> - modifying [Issue2] ?
>>> Or you do this in your original patch?
>> If you send a v2 along that lines, I'll probably pick your patch into my
>> series.  Should work even in case your series gets merged first.
> Good idea. I will send a separate v2 patch which also include the
> above change mentioned in [Issue1].
After thinking twice, I think move the above change mentioned in [Issue1]
to patch 7/7 is better. Thus my next separate v2 will not include it.
>>
>>> BTW, for your patch 24/31, the updated passed errp for vnc_init_func
>>> is &error_fatal,
>>> then the system will exit(1) when running error_propagate(...) which 
>>> calls
>>> error_handle_fatal(...). This means the following two lines will not
>>> be touched.
>>> But if we want the following prepended error message, could we move it
>>> earlier than
>>> the error_propagare? I mean:
>>>
>>>       if (local_err != NULL) {
>>> -        error_reportf_err(local_err, "Failed to start VNC server: ");
>>> -        exit(1);
>>> +        error_prepend(&local_err, "Failed to start VNC server: ");
>>> +        error_propagate(errp, local_err);
>>> +        return -1;
>>>       }
>> Both
>>
>>           error_propagate(errp, local_err);
>>           error_prepend(errp, "Failed to start VNC server: ");
>>
>> and
>>
>>          error_prepend(&local_err, "Failed to start VNC server: ");
>>          error_propagate(errp, local_err);
>>
>> work.  The former is slightly more efficient when errp is null. But
>> you're right, it fails to include the "Failed to start VNC server: "
>> prefix with &error_fatal.  Thus, the latter is preferrable.
>>
>>
> Have a nice day, thanks
> Fei
>
>
>
diff mbox series

Patch

diff --git a/include/ui/console.h b/include/ui/console.h
index fb969caf70..c17803c530 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -453,7 +453,7 @@  void qemu_display_early_init(DisplayOptions *opts);
 void qemu_display_init(DisplayState *ds, DisplayOptions *opts);
 
 /* vnc.c */
-void vnc_display_init(const char *id);
+void vnc_display_init(const char *id, Error **errp);
 void vnc_display_open(const char *id, Error **errp);
 void vnc_display_add_client(const char *id, int csock, bool skipauth);
 int vnc_display_password(const char *id, const char *password);
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index 929391f85d..8807d7217c 100644
--- a/ui/vnc-jobs.c
+++ b/ui/vnc-jobs.c
@@ -331,15 +331,18 @@  static bool vnc_worker_thread_running(void)
     return queue; /* Check global queue */
 }
 
-void vnc_start_worker_thread(void)
+bool vnc_start_worker_thread(Error **errp)
 {
     VncJobQueue *q;
 
-    if (vnc_worker_thread_running())
-        return ;
+    if (vnc_worker_thread_running()) {
+        goto out;
+    }
 
     q = vnc_queue_init();
     qemu_thread_create(&q->thread, "vnc_worker", vnc_worker_thread, q,
                        QEMU_THREAD_DETACHED);
     queue = q; /* Set global queue */
+out:
+    return true;
 }
diff --git a/ui/vnc-jobs.h b/ui/vnc-jobs.h
index 59f66bcc35..14640593db 100644
--- a/ui/vnc-jobs.h
+++ b/ui/vnc-jobs.h
@@ -37,7 +37,7 @@  void vnc_job_push(VncJob *job);
 void vnc_jobs_join(VncState *vs);
 
 void vnc_jobs_consume_buffer(VncState *vs);
-void vnc_start_worker_thread(void);
+bool vnc_start_worker_thread(Error **errp);
 
 /* Locks */
 static inline int vnc_trylock_display(VncDisplay *vd)
diff --git a/ui/vnc.c b/ui/vnc.c
index cf221c83cc..f3806e76db 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3205,7 +3205,7 @@  static const DisplayChangeListenerOps dcl_ops = {
     .dpy_cursor_define    = vnc_dpy_cursor_define,
 };
 
-void vnc_display_init(const char *id)
+void vnc_display_init(const char *id, Error **errp)
 {
     VncDisplay *vd;
 
@@ -3235,7 +3235,9 @@  void vnc_display_init(const char *id)
     vd->connections_limit = 32;
 
     qemu_mutex_init(&vd->mutex);
-    vnc_start_worker_thread();
+    if (!vnc_start_worker_thread(errp)) {
+        return;
+    }
 
     vd->dcl.ops = &dcl_ops;
     register_displaychangelistener(&vd->dcl);
@@ -4079,7 +4081,11 @@  int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
     char *id = (char *)qemu_opts_id(opts);
 
     assert(id);
-    vnc_display_init(id);
+    vnc_display_init(id, &local_err);
+    if (local_err) {
+        error_reportf_err(local_err, "Failed to init VNC server: ");
+        exit(1);
+    }
     vnc_display_open(id, &local_err);
     if (local_err != NULL) {
         error_reportf_err(local_err, "Failed to start VNC server: ");