And however the problem is not different tasks are trying to access the semaphore. Is the same task that is calling FreeSysObject on a VALID semaphore that is causing a DSI into kernel.
And for me a DSI in a system component is not so normal as you said. At least it should protected by bad code. I've also printed some test lines:
CLIB_CONSTRUCTOR: dirent_lock = 0x5e4b4160 - TASK = 0x5fdc5510
__dirent_lock = 0x5e4b4160 - TASK = 0x5fdc5510
__dirent_unlock = 0x5e4b4160 - TASK = 0x5fdc5510
__dirent_lock = 0x5e4b4160 - TASK = 0x5fdc5510
__dirent_unlock = 0x5e4b4160 - TASK = 0x5fdc5510
__dirent_lock = 0x5e4b4160 - TASK = 0x5fdc5510
__dirent_unlock = 0x5e4b4160 - TASK = 0x5fdc5510
__dirent_lock = 0x5e4b4160 - TASK = 0x5fdc5510
__dirent_unlock = 0x5e4b4160 - TASK = 0x5fdc5510
semaphore1 = 0x5b4acd20 - 0x5fdc5510
semaphore2 = 0x5b4acd20 - 0x5fdc5510
semaphore3 = 0x00000000 - 0x5fdc5510
semaphore1 = 0x5b4acd50 - 0x5fdc5510
semaphore2 = 0x5b4acd50 - 0x5fdc5510
semaphore3 = 0x00000000 - 0x5fdc5510
CLIB_DESTRUCTOR = 0x5e4b4160 - TASK = 0x5fdc5510
semaphore1 = 0x5e4b4160 - 0x5fdc5510
semaphore2 = 0x5e4b4160 - 0x5fdc5510
In the CLIB_CONSTRUCTOR is created the dirent lock and used without any problem (see lock/unlock) operations.
semapore1/2/3 are taken from 
void 
__delete_semaphore(struct SignalSemaphore *semaphore)
{
    Printf("semaphore1 = %p - %p\n", semaphore, FindTask(NULL));
    if (semaphore != NULL)
    {
        Printf("semaphore2 = %p - %p\n", semaphore, FindTask(NULL));
        FreeSysObject(ASOT_SEMAPHORE, semaphore);
        semaphore = NULL;
        Printf("semaphore3 = %p - %p\n", semaphore, FindTask(NULL));
    }
}
and so that function is workin correctly and as you can see the semaphore is set to NULL correctly.
in CLIB_DESTRUCTOR is called the same funcion that crash in FreeSysObject. And the Semaphore is not locked so is not the problem.
So where is the problem?