re-entrant stdio example for multithreaded semihosting

Asked by Joe Gorse

Hello,

I've been having some trouble extending the semihost.c to a multi-threaded environment. My problem is very similar to:
http://forum.chibios.org/phpbb/viewtopic.php?f=16&t=1156&p=10637#p10637

It appears to be a newlib issue, though it is difficult to ascertain exactly what each variant of newlib across toolchains needs in order to make printf() work. Any pointers on debugging newlib environments or examples for avoiding the issues in the first place will be much appreciated.

Thanks.

Question information

Language:
English Edit question
Status:
Answered
For:
GNU Arm Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Last query:
Last reply:
Revision history for this message
chengbin (can-finner) said :
#1

I doubt the semihosting works in multi thread scenario. To support mutli thread, one has to implement target syscalls in compliance with rules as documented in one of the newlib.h.
But I know little about ChibiOs and its multi thread problem with semihosting, so may be talking something wrong.

Whereas in fact it's easy to debug newlib/libgloss in single thread environment. You can rebuild newlib with debug info (even with -O0), install it in toolchain directory and replace old ones; link against it; then debug it along with applications.

Hoping this can help. And we do want to help on this issue to explore multi-thread support in semihosting.
Thanks.

Revision history for this message
Joe Gorse (jhgorse) said :
#2

I have been having trouble building with ./build-toolchain --debug (see https://answers.launchpad.net/gcc-arm-embedded/+question/229127), though I think we are almost there.

Regarding ChibiOS/RT, I have a few examples that appear to work in single thread mode, but not the reentrant newlib or newlib-nano printf()'s (even though it is still single thread mode).

ChibiOS/RT may be able to handle multi-threaded semihosting in a similar way that it handles it's SDx class serial driver, which is a locking queue. Right now I have extended the BaseChannel class to some barebones semihosting functions, such as SYS_WRITE 0x05 that looks like this (without the wrapper code for BaseChannel):

static size_t shwrite(BaseChannel *stream, const char *ptr, size_t size)
{
  (void)stream;
  uint32_t retval = -1;
  static uint32_t args[3]; // 3 word block
  args[0] = 1; // file handle, i.e. from SYS_OPEN
  args[1] = (uint32_t)ptr; // ptr to write buffer
  args[2] = size; // number of bytes to be written
  // Extended asm
  // http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#s5
  // asm( asm template : output operands : input ops : clobbered registers );
  asm("mov r0, #0x05\n" // r0 <= SYS_WRITE
      "mov r1, %1\n" // r1 <= ptr_to_3_word_block(args)
      "bkpt 0x00ab" // ARM semihosting breakpoint call
      : "=r" (retval) // out to register.
      : "r" (args) // in on register.
      : "r0", "r1" ); // clobbered registers
  return retval; // 0 if successful or # bytes not written
}

int main(void) {
  uint8_t str1[] = "Raw DeadSemiBeef!\n";
  halInit();
  chSysInit();

  shwrites(chp, str1, NULL);
  return 0;
}

Can you help with this problem?

Provide an answer of your own, or ask Joe Gorse for more information if necessary.

To post a message you must log in.