Skip to content

Broken build on OS X (incompatible pthread_setname_np API)

Build is broken on OS X because it is only possible to set thread name for the current thread and pthread_setname_np accepts a single argument. This function appeared in 10.6. If that OS version needs to be supported, the best thing that can be done is conditional compilation. A short summary of inconsistencies between different *nix systems can be found here: http://stackoverflow.com/questions/2369738/can-i-set-the-name-of-a-thread-in-pthreads-linux/7989973#7989973

The error log:

rts/posix/OSThreads.c:138:30:
     error: too many arguments to function call, expected 1, have 2
        pthread_setname_np(*pId, name);
        ~~~~~~~~~~~~~~~~~~       ^~~~

/usr/include/pthread.h:471:1:
     note: 'pthread_setname_np' declared here
__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2)
^

/usr/include/Availability.h:159:50:
     note: expanded from macro '__OSX_AVAILABLE_STARTING'
        #define __OSX_AVAILABLE_STARTING(_osx, _ios) __AVAILABILITY_INTERNAL##_osx
                                                     ^

<scratch space>:65:1:  note: expanded from here
__AVAILABILITY_INTERNAL__MAC_10_6
^

/usr/include/AvailabilityInternal.h:3912:72:
     note: expanded from macro '__AVAILABILITY_INTERNAL__MAC_10_6'
                #define __AVAILABILITY_INTERNAL__MAC_10_6                  __attribute__((availability(macosx,introduced=10.6)))
                                                                           ^
1 error generated.

I can see two possible solutions for OS X:

  1. disable setting thread name by conditional compilation.
  2. write some trampoline code to work around the fact that it is only possible to set thread name for the current thread.

The latter would look like this:

struct wrapper {
    char *name;
    void *param;
    void *(*cont)(void *);
};

void *trampoline(void *ctx) {
  struct wrapper *params = (struct wrapper *)ctx;
  void *param = params->param;
  void *(*cont)(void *) = params->cont;

#ifdef MACOSX
  pthread_setname_np(params->name);
#elif
  pthread_setname_np(pthread_self(), params->name);
#endif
  free(params);

  return cont(param);
}

int
createOSThread (OSThreadId* pId, char *name,
                OSThreadProc *startProc, void *param)
{
  struct wrapper *ctx = malloc(sizeof(struct wrapper));
  
  ctx->name = name;
  ctx->cont = startProc;
  ctx->param = param;

  int result = pthread_create(pId, NULL, (void *(*)(void *))trampoline, &ctx);
  if (!result) {
    pthread_detach(*pId);
  } else {
    free(ctx);
  }
  return result;
}

It looks very hackish and I think it'd be better to go with (1), since the original change was made for debugging purposes.

Trac metadata
Trac field Value
Version 7.9
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC hvr, simonmar
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information