Bug #64138 pthread_attr_set_schedparam still called with a bogus priority value
Submitted: 26 Jan 2012 19:25 Modified: 18 Mar 2012 18:48
Reporter: Mark Callaghan Email Updates:
Status: Won't fix Impact on me:
None 
Category:MySQL Server: Compiling Severity:S3 (Non-critical)
Version:5.1 OS:Any
Assigned to: CPU Architecture:Any

[26 Jan 2012 19:25] Mark Callaghan
Description:
I think this problem is still in trunk.

mysys/my_pthread.c has this code:

#ifndef my_pthread_attr_setprio
void my_pthread_attr_setprio(pthread_attr_t *attr, int priority)
{
#ifdef HAVE_PTHREAD_SETSCHEDPARAM
  struct sched_param tmp_sched_param;
  bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
  tmp_sched_param.sched_priority=priority;
  VOID(pthread_attr_setschedparam(attr,&tmp_sched_param));
#endif
}
#endif

It can be called by this code from sql/mysqld.cc

  if (!(opt_specialflag & SPECIAL_NO_PRIOR))
    my_pthread_attr_setprio(&connection_attrib,WAIT_PRIOR);

There are two problems in my_pthread_attr_setprio
1) it ignores the return value from pthread_attr_setschedparam - my favorite problem
2) it uses a bogus value (WAIT_PRIOR == 8 for me) for the SCHED_OTHER scheduler
see http://linux.die.net/man/2/sched_get_priority_min

Older versions of glibc tolerate the bogus value. Newer versions return an error.

How to repeat:
I added printfs to understand the problem. I get errors with glibc 2.13. There are no errors with glibc 2.5

#ifndef my_pthread_attr_setprio
void my_pthread_attr_setprio(pthread_attr_t *attr, int priority)
{
#ifdef HAVE_PTHREAD_SETSCHEDPARAM
  int r;
  struct sched_param tmp_sched_param;
  bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
  tmp_sched_param.sched_priority=priority;
  r = (pthread_attr_setschedparam(attr,&tmp_sched_param));
  fprintf(stderr, "setschedpararm to priority %d returns %d\n", priority, r);

  if (r || 1) {
    perror("setschedparam failed\n");
    r= sched_get_priority_max(SCHED_FIFO); fprintf(stderr, "maxprio for FIFO is %d\n", r);
    r= sched_get_priority_max(SCHED_RR); fprintf(stderr, "maxprio for RR is %d\n", r);
    r= sched_get_priority_max(SCHED_BATCH); fprintf(stderr, "maxprio for BATCH is %d\n", r);
    r= sched_get_priority_max(SCHED_OTHER); fprintf(stderr, "maxprio for OTHER is %d\n", r);
    r = sched_getscheduler(0); fprintf(stderr, "sched is %d, FIFO/RR/BATCH/OTHER %d/%d/%d/%d\n", r, SCHED_FIFO, SCHED_RR, SCHED_BATCH, SCHED_OTHER);
  }
#endif
}
#endif

Suggested fix:
1) check error return values
2) don't use bogus priority values
[26 Jan 2012 19:28] Mark Callaghan
Looking at trunk again, WAIT_PRIOR is not used so this might be limited to 5.1
[26 Jan 2012 20:09] Mark Callaghan
Our local linux guru explained that the call fails on new versions of glibc because of:

It seems to be related to this commit: http://repo.or.cz/w/glibc.git/commitdiff/14ffbc8350791ff0f33ccc65af26ebaa1b520132. old glibc succeeds because its not trying to call sched_setscheduler() and defers the syscalls until pthread_create().
[27 Jan 2012 0:03] Sveta Smirnova
Thank you for the report.

Verified as described.
[27 Jan 2012 1:36] Mark Callaghan
Work was done for:
http://bugs.mysql.com/bug.php?id=35164
http://bugs.mysql.com/bug.php?id=37536
[27 Jan 2012 17:59] Sveta Smirnova
This is only 5.1 issue: this code does not exist since 5.5
[27 Jan 2012 18:16] Davi Arnaut
There was a decision to not fix this in 5.1 as it would either involve an incompatible change or cause adverse effects on some specific platforms.