There's no time limit, the implementation has to keep around the "return value" as long as the process itself is alive to make it available to a join.
The POSIX definition for pthread_exit
simply says:
The
pthread_exit()
function shall terminate the calling thread and make the valuevalue_ptr
available to any successful join with the terminating thread.
Doesn't matter whether the join was initiated before the exit, or years later, or whether there was only one additional thread or hundreds.