Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Windows Mutex functions (CreateMutex, OpenMutex, ReleaseMutex) #971

Merged
merged 1 commit into from
Jun 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java
Original file line number Diff line number Diff line change
Expand Up @@ -3648,4 +3648,136 @@ boolean GetProcessTimes(HANDLE hProcess, FILETIME lpCreationTime, FILETIME lpExi
* information, call GetLastError.
*/
boolean GetProcessIoCounters(HANDLE hProcess, WinNT.IO_COUNTERS lpIoCounters);

/**
* Creates or opens a named or unnamed mutex object.
*
* @param lpMutexAttributes
*
* A pointer to a {@link WinBase.SECURITY_ATTRIBUTES} structure. If this
* parameter is NULL, the mutex handle cannot be inherited by child
* processes.
*
* <p>
* The lpSecurityDescriptor member of the structure specifies a security
* descriptor for the new mutex. If lpMutexAttributes is NULL, the mutex
* gets a default security descriptor. The ACLs in the default security
* descriptor for a mutex come from the primary or impersonation token of
* the creator.</p>
*
* @param bInitialOwner
*
* If this value is TRUE and the caller created the mutex, the calling
* thread obtains initial ownership of the mutex object. Otherwise, the
* calling thread does not obtain ownership of the mutex. To determine if
* the caller created the mutex, see the Return Values section.
*
* @param lpName
*
* The name of the mutex object. The name is limited to
* {@link WinDef#MAX_PATH} characters. Name comparison is case sensitive.
*
* <p>
* If lpName matches the name of an existing named mutex object, this
* function requests the {@link WinBase#MUTEX_ALL_ACCESS} access right. In
* this case, the bInitialOwner parameter is ignored because it has already
* been set by the creating process. If the lpMutexAttributes parameter is
* not NULL, it determines whether the handle can be inherited, but its
* security-descriptor member is ignored.</p>
*
* <p>
* If lpName is NULL, the mutex object is created without a name.</p>
*
* <p>
* If lpName matches the name of an existing event, semaphore, waitable
* timer, job, or file-mapping object, the function fails and the
* {@link com.sun.jna.Native#getLastError()} function returns
* {@link WinError#ERROR_INVALID_HANDLE}. This occurs because these objects
* share the same namespace.</p>
*
* <p>
* The name can have a "Global\" or "Local\" prefix to explicitly create the
* object in the global or session namespace. The remainder of the name can
* contain any character except the backslash character (\).</p>
*
* @return
*
* If the function succeeds, the return value is a handle to the newly
* created mutex object.
*
* <p>
* If the function fails, the return value is NULL. To get extended error
* information, call {@link com.sun.jna.Native#getLastError()}.</p>
*
* <p>If the mutex is a named mutex and the object existed before this function
* call, the return value is a handle to the existing object,
* {@link com.sun.jna.Native#getLastError()} returns
* {@link WinError#ERROR_ALREADY_EXISTS}, bInitialOwner is ignored, and the
* calling thread is not granted ownership. However, if the caller has
* limited access rights, the function will fail with
* {@link WinError#ERROR_ACCESS_DENIED} and the caller should use the
* {@link #OpenMutex} function.</p>
*/
HANDLE CreateMutex(SECURITY_ATTRIBUTES lpMutexAttributes,
boolean bInitialOwner,
String lpName);

/**
* Opens an existing named mutex object.
*
* @param dwDesiredAccess
*
* The access to the mutex object. Only the {@link WinNT#SYNCHRONIZE} access
* right is required to use a mutex; to change the mutex's security, specify
* {@link WinBase#MUTEX_ALL_ACCESS}.
*
* @param bInheritHandle
*
* If this value is TRUE, processes created by this process will inherit the
* handle. Otherwise, the processes do not inherit this handle.
*
* @param lpName
*
* The name of the mutex to be opened. Name comparisons are case sensitive.
*
* <p>
* This function can open objects in a private namespace.</p>
*
* <p>
* Terminal Services: The name can have a "Global\" or "Local\" prefix to
* explicitly open an object in the global or session namespace. The
* remainder of the name can contain any character except the backslash
* character (\).</p>
*
* @return
*
* If the function succeeds, the return value is a handle to the mutex object.
*
* <p>If the function fails, the return value is NULL. To get extended error
* information, call {@link com.sun.jna.Native#getLastError()}.</p>
*
* <p>If a named mutex does not exist, the function fails and
* {@link com.sun.jna.Native#getLastError()} returns
* ERROR_FILE_NOT_FOUND.</p>
*/
HANDLE OpenMutex(int dwDesiredAccess,
boolean bInheritHandle,
String lpName);

/**
* Releases ownership of the specified mutex object.
*
* @param handle
*
* A handle to the mutex object. The CreateMutex or OpenMutex function
* returns this handle.
*
* @return
*
* If the function succeeds, the return value is nonzero.
*
* <p>If the function fails, the return value is zero. To get extended error
* information, call {@link com.sun.jna.Native#getLastError()}.</p>
*/
boolean ReleaseMutex(HANDLE handle);
}
4 changes: 4 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/WinBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -2557,4 +2557,8 @@ interface EnumResNameProc extends Callback {
* be set.
*/
int ES_USER_PRESENT = 0x00000004;


int MUTEX_MODIFY_STATE = WinNT.MUTANT_QUERY_STATE;
int MUTEX_ALL_ACCESS = WinNT.MUTANT_ALL_ACCESS;
}
4 changes: 4 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/WinNT.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ public interface WinNT extends WinError, WinDef, WinBase, BaseTSD {

int SPECIFIC_RIGHTS_ALL = 0x0000FFFF;

int MUTANT_QUERY_STATE = 0x0001;
int MUTANT_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE
| MUTANT_QUERY_STATE;

//
// Token Specific Access Rights.
//
Expand Down
53 changes: 53 additions & 0 deletions contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
import com.sun.jna.platform.win32.WinNT.OSVERSIONINFOEX;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.ShortByReference;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import junit.framework.TestCase;

Expand Down Expand Up @@ -1696,4 +1698,55 @@ public void testSetThreadExecutionState() {

Kernel32.INSTANCE.SetThreadExecutionState(originalExecutionState);
}

public void testMutex() throws InterruptedException {
HANDLE mutexHandle = Kernel32.INSTANCE.CreateMutex(null, true, "JNA-Test-Mutex");

assertNotNull(mutexHandle);

final CountDownLatch preWait = new CountDownLatch(1);
final CountDownLatch postWait = new CountDownLatch(1);
final CountDownLatch postRelease = new CountDownLatch(1);

final Exception[] exceptions = new Exception[1];
Thread t = new Thread() {
@Override
public void run() {
try {
HANDLE mutexHandle2 = Kernel32.INSTANCE.OpenMutex(WinNT.SYNCHRONIZE, false, "JNA-Test-Mutex");
try {
assertNotNull(mutexHandle2);
preWait.countDown();
int result = Kernel32.INSTANCE.WaitForSingleObject(mutexHandle2, WinBase.INFINITE);
assertEquals(result, WinBase.WAIT_OBJECT_0);
postWait.countDown();
} finally {
Kernel32.INSTANCE.ReleaseMutex(mutexHandle2);
Kernel32.INSTANCE.CloseHandle(mutexHandle2);
postRelease.countDown();
}
} catch (Exception ex) {
exceptions[0] = ex;
}
}
};

t.start();

assertTrue(preWait.await(2, TimeUnit.SECONDS));

Kernel32.INSTANCE.ReleaseMutex(mutexHandle);

assertTrue(postWait.await(2, TimeUnit.SECONDS));

Kernel32.INSTANCE.CloseHandle(mutexHandle);

assertTrue(postRelease.await(2, TimeUnit.SECONDS));

assertNull(exceptions[0]);

mutexHandle = Kernel32.INSTANCE.OpenMutex(WinNT.SYNCHRONIZE, false, "JNA-Test-Mutex");

assertNull(mutexHandle);
}
}