Re: [PATCH] make setpriority POSIX compliant; introduce PRIO_THREAD extension

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Michael Kerrisk
Date: Tuesday, September 9, 2008 - 8:45 am

Denys,

On 9/1/08, Denys Vlasenko <dvlasenk@redhat.com> wrote:

Tested-by: Michael Kerrisk <mtk.manpages@gmail.com>

Please do CC me on API changes, so that they might get documented in
the man pages.

Thanks for this work.  (I'm not sure whether or not it's a response to
my bug report, http://bugzilla.kernel.org/show_bug.cgi?id=6258 )

I tested your patch.  Most things seem to work as I would expect, but
there is one strangeness.

I would expect
setpriority(PRIO_PROCESS, getpid())
and
setpriority(PRIO_PROCESS, 0)
to have the same affect (because: which == PRIO_PRCESS, who == 0
conventionally means "the calling process").

But they do not: the latter call only changes the priority of the
calling thread.  Is this intended?

My test program is at the end of this mail.  Here are two tests
demonstrating the behavior in each of the above cases:

$ sudo ./thread_nice_test p p
root's password:
main(): TID = 6574, PID = 6574
main(): initial nice value is 0

Thread 1: TID = 6578
Thread 2: TID = 6579
Loop 0
    process nice value is 0
    main(): nice value is 0
    Thread 1: nice value is 0
    Thread 2: nice value is 0
Thread 1: setpriority() succeeded (0, 6574)
Loop 1
    process nice value is -10
    main(): nice value is -10
    Thread 1: nice value is -10
    Thread 2: nice value is -10
Loop 2
    process nice value is -10
    main(): nice value is -10
    Thread 1: nice value is -10
    Thread 2: nice value is -10


$ sudo ./thread_nice_test p 0
main(): TID = 6590, PID = 6590
main(): initial nice value is 0

Thread 1: TID = 6594
Thread 2: TID = 6595
Loop 0
    process nice value is 0
    main(): nice value is 0
    Thread 1: nice value is 0
    Thread 2: nice value is 0
Thread 1: setpriority() succeeded (0, 0)
Loop 1
    process nice value is -10
    main(): nice value is 0
    Thread 1: nice value is -10
    Thread 2: nice value is 0
Loop 2
    process nice value is -10
    main(): nice value is 0
    Thread 1: nice value is -10
    Thread 2: nice value is 0

=====

/* thread_nice_test.c

   Copyright 2008, Linux Foundation, written by Michael Kerrisk
        <mtk.manpages@gmail.com>
   Licensed under GNU GPL version 2 or later

   Creates two subthreads.
   The first thread does a setpriority() with arguments
   based on command-line arguments.
   The main() program loops, using getpriority() to monitor
   priority of all threads, and the process as a whole.
*/
#define _GNU_SOURCE
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <limits.h>
#include <string.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

#define PRIO_THREAD 3

#define errExit(msg)            { perror(msg); exit(EXIT_FAILURE); }

#define errExitEN(en, msg)      { errno = en; perror(msg); \
                                  exit(EXIT_FAILURE); }

#define fatal(msg)              { fprintf(stderr, "%s\n", msg); \
                                  exit(EXIT_FAILURE); }

#define NEW_NICE -10

static pid_t
gettid(void)
{
    return syscall(SYS_gettid);
}

static pid_t t1_tid, t2_tid, main_tid;
static char cwhich, cwho;

static void *
tf1_nice(void *x)
{
    int which, who;

    t1_tid = gettid();
    printf("Thread 1: TID = %ld\n", (long) gettid());

    sleep(1);

    which = (cwhich == 'p') ? PRIO_PROCESS :
            (cwhich == 't') ? PRIO_THREAD :
            9999;       /* Invalid value */
    who =   (cwho == '0') ? 0 :
            (cwho == 't') ? gettid() :
            (cwho == 'p') ? getpid() :
            (cwho == 'm') ? main_tid :
            -1;                 /* Invalid value */
    if (setpriority(which, who, NEW_NICE) == -1)
        errExit("setpriority");

    printf("Thread 1: setpriority() succeeded (%d, %d)\n", which, who);

    sleep(10);
    printf("Thread 1 terminating\n");
    return NULL;
}

static void *
tf2_nice(void *x)
{
    t2_tid = gettid();
    printf("Thread 2: TID = %ld\n", (long) gettid());

    sleep (10);

    printf("Thread 2 terminating\n");
    return NULL;
}


int
main(int argc, char *argv[])
{
    pthread_t t1, t2;
    int s;
    int nval;
    int j;

    if (argc != 3) {
        fprintf(stderr, "Usage: %s <which> <who>\n", argv[0]);
        fprintf(stderr, "which is\n");
        fprintf(stderr, "    p   PRIO_PROCESS\n");
        fprintf(stderr, "    t   PRIO_THREAD\n");
        fprintf(stderr, "who is:\n");
        fprintf(stderr, "    0   0\n");
        fprintf(stderr, "    t   gettid()\n");
        fprintf(stderr, "    p   getpid()\n");
        fprintf(stderr, "    m   TID of main()\n");
        exit(EXIT_FAILURE);
    }

    main_tid = gettid();
    cwhich = argv[1][0];
    cwho = argv[2][0];

    printf("main(): TID = %ld, PID = %ld\n",
            (long) gettid(), (long) getpid());

    errno = 0;
    nval = getpriority(PRIO_PROCESS, gettid());
    if (nval == -1 && errno != 0)
        errExit("getpriority");
    printf("main(): initial nice value is %d\n", nval);


    printf("\n");

    s = pthread_create(&t1, NULL, tf1_nice, (void *) 1);
    if (s != 0)
        errExitEN(s, "pthread_create");

    s = pthread_create(&t2, NULL, tf2_nice, (void *) 2);
    if (s != 0)
        errExitEN(s, "pthread_create");

    usleep(200000);  /* Allow time for subthreads to set global vars */

    for (j = 0; j < 3; j++) {
        printf("Loop %d\n", j);
        errno = 0;
        nval = getpriority(PRIO_PROCESS, gettid());
        if (nval == -1 && errno != 0)
            errExit("getpriority");
        printf("    process nice value is %d\n", nval);

        errno = 0;
        nval = getpriority(PRIO_THREAD, gettid());
        if (nval == -1 && errno != 0)
            errExit("getpriority");
        printf("    main(): nice value is %d\n", nval);

        errno = 0;
        nval = getpriority(PRIO_THREAD, t1_tid);
        if (nval == -1 && errno != 0)
            errExit("getpriority");
        printf("    Thread 1: nice value is %d\n", nval);

        errno = 0;
        nval = getpriority(PRIO_THREAD, t2_tid);
        if (nval == -1 && errno != 0)
            errExit("getpriority");
        printf("    Thread 2: nice value is %d\n", nval);

        sleep(2);
    }

    exit(EXIT_SUCCESS);
} /* main */
--
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
Re: [PATCH] make setpriority POSIX compliant; introduce PR ..., Michael Kerrisk, (Tue Sep 9, 8:45 am)
Re: [PATCH] make setpriority POSIX compliant; introduce PR ..., Christoph Hellwig, (Wed Sep 10, 5:08 am)