kstrdup() functioning

  • What does duplicating a string do?

  • With respect to semaphores why is important to duplicate a semaphore and

  • in a case that it kstrdup() returns null does it mean that the semaphore already has been allocated in the memory and then the semaphore is just freed?

Duplicating a string is a pretty simple operation. Check the definition of kstrdup to see, and it works how you would expect (note it doesn’t null check the input pointer). Space is allocated, and the string is copied into the new space.

Duplicating a semaphore would just involve duplicating it’s state, so basically just copying what is inside it (and it’s referenced structures) into some new memory. It’s tricky thing to do because while you would duplicate the semaphore, other threads might have been responsible for setting the state of that semaphore. Since a semaphore holds a count that could be zero, if you duplicate it and expect the same thread that decremented the count to increment the count, you could be waiting awhile (like forever, since it doesn’t have a reference to the copied semaphore). Copying one while it’s being used is probably a bad idea, but if it needs to be done for some reason you should be aware of the problems that could arise.

(edited) In userspace malloc would set errno to let you know what went wrong, but there no errno in the kernel. NULL is all you get if there is a failure.

Does that help?


I get the duplicating part, but now I have a follow up question. If kmalloc allocates memory for a structure, what does checking if that pointer points to NULL, do? Does that mean kmalloc failed?

Yes, getting NULL from kmalloc means the operation failed.

1 Like

The way I am interpreting it when kmalloc returns NULL it has run out of space to allocate the memory. Essentially an out of memory error. That may help your understanding.


Yes, if it’s null it means there has been a failure. I think errno will be set in that case to tell you exactly what happened.

We’ll discuss errno in a future lecture, but it’s a C library construction. So it does not get set in the kernel.

Longer version: C programs typically use C library system call wrappers that do not map down exactly to the underlying kernel system call. For example, open (from the C library) calls sys_open (a kernel system call), but also does things like setting errno.

FWIW, here’s the relevant wrapper code used by all OS/161 userland system calls. (Of course it’s in assembly code.) From userland/lib/libc/arch/mips/syscalls-mips.S:

 * Now, the shared system call code.
 * The MIPS syscall ABI is as follows:
 *    On entry, call number in v0. The rest is like a normal function
 *    call: four args in a0-a3, the other args on the stack.
 *    On successful return, zero in a3 register; return value in v0
 *    (v0 and v1 for a 64-bit return value).
 *    On error return, nonzero in a3 register; errno value in v0.
 * The use of a3 as a return register to hold the success flag is
 * gross, but I didn't make it up.
 * Note that by longstanding Unix convention and POSIX decree, errno
 * is not to be set unless the call actually fails.

   .set noreorder
   .type __syscall,@function
   .ent __syscall
   syscall              /* make system call */
   beq a3, $0, 1f       /* if a3 is zero, call succeeded */
   nop      /* delay slot */
   sw v0, errno        /* call failed: store errno */
   li v1, -1    /* and force return value to -1 */
   li v0, -1
   j ra     /* return */
   nop      /* delay slot */
   .end __syscall
   .set reorder

So you can see errno getting set here.

1 Like