Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Windows service cannot see named semaphore

I'm trying to mediate a small windows service, making it to wait for a signal from another process during startup. For sure I know that such approach may (or even will) sometimes lead to service startup timeout. That's not the case.

The problem is with named System.Thread.Sempaphore I use for mediation purposes. Semaphore is created and acquired somewhere else using following construct. There's no change GC has it as I explicitly break the execution right below given line for test purposes.

Boolean newOne;
System.Threading.Semaphore rootSemaphore = 
    new System.Threading.Semaphore(1, 1, "DummyServiceSemaphore", out newOne);

Code above works well, obviously. Following code works well when being executed in debug mode or under console application:

Boolean createdNew;
System.Threading.Semaphore semaphore = 
    new System.Threading.Semaphore(1, 1, "DummyServiceSemaphore", out createdNew);
if (createdNew) 
    throw new Exception("That's not what we wanted");

Exactly the same code fails when being executed as a part of Windows service:

static class Program
{
    static void Main(string[] args)
    {
        Boolean createdNew;
        System.Threading.Semaphore semaphore = 
            new System.Threading.Semaphore(1, 1, "DummyServiceSemaphore", out createdNew);
        if (createdNew) 
            throw new Exception("That's not what we wanted");

        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] { new Dummy() };
        ServiceBase.Run(ServicesToRun);
    }
}

Why the failure?

I've been trying to use Mutex instead, however there was another issue with it - waiting application doesn't catch up when owner calls Mutex.ReleaseMutex();


UPDATE:

As per Anurag Ranjhan response I've edited semaphore creating routine as follows and the thingy now works fine:

Boolean newOne = false;

System.Security.Principal.SecurityIdentifier sid = 
    new System.Security.Principal.SecurityIdentifier(
        System.Security.Principal.WellKnownSidType.WorldSid, 
        null);

System.Security.AccessControl.SemaphoreSecurity sec = 
    new System.Security.AccessControl.SemaphoreSecurity();
sec.AddAccessRule(new System.Security.AccessControl.SemaphoreAccessRule(
    sid,
    System.Security.AccessControl.SemaphoreRights.FullControl,
    System.Security.AccessControl.AccessControlType.Allow));

System.Threading.Semaphore rootSemaphore = 
    new Semaphore(1, 1, "Global\\DummyServiceSemaphore", out newOne, sec);
like image 459
Vitaly Avatar asked Mar 30 '12 15:03

Vitaly


1 Answers

Try using with Global\ prefix

System.Threading.Semaphore rootSemaphore = 
new System.Threading.Semaphore(1, 1, @"Global\DummyServiceSemaphore", out newOne);

From the comment section of MSDN

If you're using a named Semaphore in Windows, the name you choose is governed by Kernel naming guidelines. Some of those guidelines also include the Kernel Object Namespaces1, which describes the context of the kernel object. By default, with Terminal Services installed, kernel objects like events are limited to the current Session. This is done so multiple sessions running in Terminal Services won't adversely affect one another. Kernel Object Namespaces describe using "Local", "Global" and "Session" prefixes to create kernel objects that can apply to specific namespaces and to communicate with or limit communication to processes of a specific scope.

like image 122
Raj Ranjhan Avatar answered Oct 16 '22 07:10

Raj Ranjhan