Patchwork [10/10] alpha-linux-user: Fix the getpriority syscall

login
register
mail settings
Submitter Richard Henderson
Date July 25, 2012, 10:10 p.m.
Message ID <1343254238-4727-11-git-send-email-rth@twiddle.net>
Download mbox | patch
Permalink /patch/173299/
State New
Headers show

Comments

Richard Henderson - July 25, 2012, 10:10 p.m.
Alpha uses unbiased priority values in the syscall, with the a3
return value signaling error conditions.  Therefore, properly
interpret the libc getpriority as needed for the guest rather
than passing the host value through unchanged.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/syscall.c |   20 +++++++++++++++-----
 1 files changed, 15 insertions(+), 5 deletions(-)
Peter Maydell - Aug. 2, 2012, 2:48 p.m.
On 25 July 2012 23:10, Richard Henderson <rth@twiddle.net> wrote:
> Alpha uses unbiased priority values in the syscall, with the a3
> return value signaling error conditions.  Therefore, properly
> interpret the libc getpriority as needed for the guest rather
> than passing the host value through unchanged.
>
> Signed-off-by: Richard Henderson <rth@twiddle.net>
> ---
>  linux-user/syscall.c |   20 +++++++++++++++-----
>  1 files changed, 15 insertions(+), 5 deletions(-)
>
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 2e1c1c0..b487635 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -218,7 +218,6 @@ _syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count)
>  #if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
>  _syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
>  #endif
> -_syscall2(int, sys_getpriority, int, which, int, who);
>  #if defined(TARGET_NR__llseek) && defined(__NR_llseek)
>  _syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
>            loff_t *, res, uint, wh);
> @@ -6445,10 +6444,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
>          break;
>  #endif
>      case TARGET_NR_getpriority:
> -        /* libc does special remapping of the return value of
> -         * sys_getpriority() so it's just easiest to call
> -         * sys_getpriority() directly rather than through libc. */
> -        ret = get_errno(sys_getpriority(arg1, arg2));
> +        /* Note that negative values are valid for getpriority, so we must
> +           differentiate based on errno settings.  */
> +        errno = 0;
> +        ret = getpriority(arg1, arg2);
> +        if (ret == -1 && errno != 0) {
> +            ret = get_errno(errno);
> +            break;
> +        }
> +#ifdef TARGET_ALPHA
> +        /* Return value is the unbiased priority.  Signal no error.  */
> +        ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;

Having do_syscall fish around in the cpu register struct seems a
bit ugly, but we do it elsewhere so I guess this is OK.

> +#else
> +        /* Return value is a biased priority to avoid negative numbers.  */
> +        ret = 20 - ret;
> +#endif
>          break;
>      case TARGET_NR_setpriority:
>          ret = get_errno(setpriority(arg1, arg2, arg3));

Sanity check -- it is only getpriority that has the biasing, not
setpriority?

-- PMM
Richard Henderson - Aug. 2, 2012, 3:23 p.m.
On 2012-08-02 07:48, Peter Maydell wrote:
> Sanity check -- it is only getpriority that has the biasing, not setpriority?

Correct.

r~

Patch

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 2e1c1c0..b487635 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -218,7 +218,6 @@  _syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count)
 #if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
 _syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
 #endif
-_syscall2(int, sys_getpriority, int, which, int, who);
 #if defined(TARGET_NR__llseek) && defined(__NR_llseek)
 _syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
           loff_t *, res, uint, wh);
@@ -6445,10 +6444,21 @@  abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 #endif
     case TARGET_NR_getpriority:
-        /* libc does special remapping of the return value of
-         * sys_getpriority() so it's just easiest to call
-         * sys_getpriority() directly rather than through libc. */
-        ret = get_errno(sys_getpriority(arg1, arg2));
+        /* Note that negative values are valid for getpriority, so we must
+           differentiate based on errno settings.  */
+        errno = 0;
+        ret = getpriority(arg1, arg2);
+        if (ret == -1 && errno != 0) {
+            ret = get_errno(errno);
+            break;
+        }
+#ifdef TARGET_ALPHA
+        /* Return value is the unbiased priority.  Signal no error.  */
+        ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0;
+#else
+        /* Return value is a biased priority to avoid negative numbers.  */
+        ret = 20 - ret;
+#endif
         break;
     case TARGET_NR_setpriority:
         ret = get_errno(setpriority(arg1, arg2, arg3));