Repository: LadybirdBrowser/ladybird
File: Libraries/LibThreading/Thread.cpp (C++)

Code before:
}

void Thread::start()
{
    VERIFY(!is_started());

    // Set this first so that the other thread starts out seeing m_state == Running.
    m_state = Threading::ThreadState::Running;

    int rc = pthread_create(
        &m_tid,
        // FIXME: Use pthread_attr_t to start a thread detached if that was requested by the user before the call to start().
        nullptr,
        [](void* arg) -> void* {
            auto self = adopt_ref(*static_cast<Thread*>(arg));

            {
                // pthread_setname_np expects a 16-byte or shorter null-terminated C string.
                auto thread_name = self->thread_name().substring(0, min(self->thread_name().length(), 15));
#if defined(AK_OS_MACOS)
                pthread_setname_np(thread_name.characters());
#else
                pthread_setname_np(pthread_self(), thread_name.characters());
#endif
            }

            auto exit_code = self->m_action();

            auto expected = Threading::ThreadState::Running;
            // This code might race with a call to detach().
            if (!self->m_state.compare_exchange_strong(expected, Threading::ThreadState::Exited)) {
                // If the original state was Detached, we need to set to DetachedExited instead.
                if (expected == Threading::ThreadState::Detached) {
                    if (!self->m_state.compare_exchange_strong(expected, Threading::ThreadState::DetachedExited)) {
                        dbgln("Thread logic bug: Found thread state {} while trying to set ExitedDetached state!", expected);
                        VERIFY_NOT_REACHED();
                    }
                } else {
                    dbgln("Thread logic bug: Found thread state {} while trying to set Exited state!", expected);
                    VERIFY_NOT_REACHED();
                }
            }

            return reinterpret_cast<void*>(exit_code);
        },
        &NonnullRefPtr(*this).leak_ref());

    VERIFY(rc == 0);
}

void Thread::detach()

Review comment (suggestion):
If you don't want to deal with BSD support in this PR I can fix it up later, but either you could apply this:

```suggestion
#elif defined(AK_OS_OPENBSD)
                pthread_set_name_np(pthread_self(), thread_name.characters());
#elif defined(AK_OS_NETBSD)
                pthread_setname_np(pthread_self(), "%s", (void *)thread_name.characters());
#else
```

or just hide it behind something like:

```suggestion
#elif defined(AK_OS_LINUX) || defined(AK_OS_FREEBSD) || defined(AK_OS_WINDOWS)
```

and maybe throw a dbgln about it being unsupported although that might be quite verbose.

Code after:
}

void Thread::start()
{
    VERIFY(!is_started());

    // Set this first so that the other thread starts out seeing m_state == Running.
    m_state = Threading::ThreadState::Running;

    int rc = pthread_create(
        &m_tid,
        // FIXME: Use pthread_attr_t to start a thread detached if that was requested by the user before the call to start().
        nullptr,
        [](void* arg) -> void* {
            auto self = adopt_ref(*static_cast<Thread*>(arg));

            {
                // pthread_setname_np expects a 16-byte or shorter null-terminated C string.
                auto thread_name = self->thread_name().substring(0, min(self->thread_name().length(), 15));
#if defined(AK_OS_MACOS)
                pthread_setname_np(thread_name.characters());
#elif defined(AK_OS_OPENBSD)
                pthread_set_name_np(pthread_self(), thread_name.characters());
#elif defined(AK_OS_NETBSD)
                pthread_setname_np(pthread_self(), "%s", const_cast<char*>(thread_name.characters()));
#else
                pthread_setname_np(pthread_self(), thread_name.characters());
#endif
            }

            auto exit_code = self->m_action();

            auto expected = Threading::ThreadState::Running;
            // This code might race with a call to detach().
            if (!self->m_state.compare_exchange_strong(expected, Threading::ThreadState::Exited)) {
                // If the original state was Detached, we need to set to DetachedExited instead.
                if (expected == Threading::ThreadState::Detached) {
                    if (!self->m_state.compare_exchange_strong(expected, Threading::ThreadState::DetachedExited)) {
                        dbgln("Thread logic bug: Found thread state {} while trying to set ExitedDetached state!", expected);
                        VERIFY_NOT_REACHED();
                    }
                } else {
                    dbgln("Thread logic bug: Found thread state {} while trying to set Exited state!", expected);
                    VERIFY_NOT_REACHED();
                }
            }

            return reinterpret_cast<void*>(exit_code);
        },
        &NonnullRefPtr(*this).leak_ref());