I'm glad you got everything working smoothly.
I saw the semaphore protecting the process list and it looked like it would mostly protect in this way, but I think that there was a case where a task had to release the semaphore before calling vTaskDelete(NULL) on itself. The race is in that moment, between releasing the semaphore and calling vTaskDelete(NULL) another task may be scheduled and decide to call vTaskDelete(that task). But I'm not certain.