Skip to content

Commit 872c004

Browse files
dbwiddismatthiasblaesing
authored andcommitted
Add Kernel32#SetProcessAffinityMask
1 parent 9cc7c06 commit 872c004

3 files changed

Lines changed: 75 additions & 8 deletions

File tree

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Features
99
--------
1010
* [#1160](https://github.com/java-native-access/jna/issues/1160): Make FileUtils#moveToTrash a varargs method - [@matthiasblaesing](https://github.com/matthiasblaesing).
1111
* [#1167](https://github.com/java-native-access/jna/pull/1167): Add `c.s.j.p.win32.Kernel32.GetProcessAffinityMask` - [@dbwiddis](https://github.com/dbwiddis).
12+
* [#1168](https://github.com/java-native-access/jna/pull/1168): Add `c.s.j.p.win32.Kernel32.SetProcessAffinityMask` - [@dbwiddis](https://github.com/dbwiddis).
1213

1314
Bug Fixes
1415
---------

contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import com.sun.jna.LastErrorException;
2727
import com.sun.jna.Native;
2828
import com.sun.jna.Pointer;
29+
import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR;
30+
import com.sun.jna.platform.win32.WinNT.HANDLE;
2931
import com.sun.jna.ptr.IntByReference;
3032
import com.sun.jna.ptr.PointerByReference;
3133
import com.sun.jna.win32.StdCallLibrary;
@@ -335,6 +337,33 @@ boolean ReadFile(HANDLE hFile, byte[] lpBuffer, int nNumberOfBytesToRead,
335337
boolean GetProcessAffinityMask(HANDLE hProcess, ULONG_PTRByReference lpProcessAffinityMask,
336338
ULONG_PTRByReference lpSystemAffinityMask);
337339

340+
/**
341+
* Sets a processor affinity mask for the threads of the specified process.
342+
*
343+
* @param hProcess
344+
* A handle to the process whose affinity mask is to be set. This
345+
* handle must have the {@link WinNT#PROCESS_SET_INFORMATION} access
346+
* right.
347+
* @param dwProcessAffinityMask
348+
* The affinity mask for the threads of the process.
349+
* <p>
350+
* On a system with more than 64 processors, the affinity mask must
351+
* specify processors in a single processor group.
352+
* @return If the function succeeds, the return value is {@code true}.
353+
* <p>
354+
* If the function fails, the return value is {@code false}. To get
355+
* extended error information, call {@link #GetLastError()}.
356+
* <p>
357+
* If the process affinity mask requests a processor that is not
358+
* configured in the system, the last error code is
359+
* {@link WinError#ERROR_INVALID_PARAMETER}.
360+
* <p>
361+
* On a system with more than 64 processors, if the calling process
362+
* contains threads in more than one processor group, the last error
363+
* code is {@link WinError#ERROR_INVALID_PARAMETER}.
364+
*/
365+
boolean SetProcessAffinityMask(HANDLE hProcess, ULONG_PTR dwProcessAffinityMask);
366+
338367
/**
339368
* Retrieves the termination status of the specified process.
340369
*

contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import com.sun.jna.Platform;
6363
import com.sun.jna.Pointer;
6464
import com.sun.jna.platform.win32.BaseTSD.SIZE_T;
65+
import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR;
6566
import com.sun.jna.platform.win32.BaseTSD.ULONG_PTRByReference;
6667
import com.sun.jna.platform.win32.Ntifs.REPARSE_DATA_BUFFER;
6768
import com.sun.jna.platform.win32.Ntifs.SymbolicLinkReparseBuffer;
@@ -464,22 +465,58 @@ public void testGetProcessIoCounters() {
464465
}
465466
}
466467

467-
public void testGetProcessAffinityMask() {
468-
int myPid = Kernel32.INSTANCE.GetCurrentProcessId();
469-
HANDLE pHandle = Kernel32.INSTANCE.OpenProcess(WinNT.PROCESS_QUERY_INFORMATION, false, myPid);
468+
public void testGetAndSetProcessAffinityMask() {
469+
// Pseudo handle, no need to close. Has PROCESS_ALL_ACCESS right.
470+
HANDLE pHandle = Kernel32.INSTANCE.GetCurrentProcess();
470471
assertNotNull(pHandle);
471472

472473
ULONG_PTRByReference pProcessAffinity = new ULONG_PTRByReference();
473474
ULONG_PTRByReference pSystemAffinity = new ULONG_PTRByReference();
474-
assertTrue(Kernel32.INSTANCE.GetProcessAffinityMask(pHandle, pProcessAffinity, pSystemAffinity));
475+
assertTrue("Failed to get affinity masks.",
476+
Kernel32.INSTANCE.GetProcessAffinityMask(pHandle, pProcessAffinity, pSystemAffinity));
475477

476478
long processAffinity = pProcessAffinity.getValue().longValue();
477479
long systemAffinity = pSystemAffinity.getValue().longValue();
478480

479-
assertEquals("Process affinity must be a subset of system affinity", processAffinity,
480-
processAffinity & systemAffinity);
481-
assertEquals("System affinity must be a superset of process affinity", systemAffinity,
482-
processAffinity | systemAffinity);
481+
if (systemAffinity == 0) {
482+
// Rare case for process to be running in multiple processor groups, where both
483+
// systemAffinity and processAffinity are 0 and we can't do anything else.
484+
assertEquals(
485+
"Both process and system affinity must be zero if this process is running in multiple processor groups",
486+
processAffinity, systemAffinity);
487+
} else {
488+
// Test current affinity
489+
assertEquals("Process affinity must be a subset of system affinity", processAffinity,
490+
processAffinity & systemAffinity);
491+
assertEquals("System affinity must be a superset of process affinity", systemAffinity,
492+
processAffinity | systemAffinity);
493+
494+
// Set affinity to a single processor in the current system
495+
long lowestOneBit = Long.lowestOneBit(systemAffinity);
496+
ULONG_PTR dwProcessAffinityMask = new ULONG_PTR(lowestOneBit);
497+
assertTrue("Failed to set affinity",
498+
Kernel32.INSTANCE.SetProcessAffinityMask(pHandle, dwProcessAffinityMask));
499+
assertTrue("Failed to get affinity masks.",
500+
Kernel32.INSTANCE.GetProcessAffinityMask(pHandle, pProcessAffinity, pSystemAffinity));
501+
assertEquals("Process affinity doesn't match what was just set", lowestOneBit,
502+
pProcessAffinity.getValue().longValue());
503+
504+
// Now try to set affinity to an invalid processor
505+
lowestOneBit = Long.lowestOneBit(~systemAffinity);
506+
// In case we have exactly 64 processors we can't do this, otherwise...
507+
if (lowestOneBit != 0) {
508+
dwProcessAffinityMask = new ULONG_PTR(lowestOneBit);
509+
assertFalse("Successfully set affinity when it should have failed",
510+
Kernel32.INSTANCE.SetProcessAffinityMask(pHandle, dwProcessAffinityMask));
511+
assertEquals("Last error should be ERROR_INVALID_PARAMETER", WinError.ERROR_INVALID_PARAMETER,
512+
Kernel32.INSTANCE.GetLastError());
513+
}
514+
515+
// Cleanup. Be nice and put affinity back where it started!
516+
dwProcessAffinityMask = new ULONG_PTR(processAffinity);
517+
assertTrue("Failed to restore affinity to original setting",
518+
Kernel32.INSTANCE.SetProcessAffinityMask(pHandle, dwProcessAffinityMask));
519+
}
483520
}
484521

485522
public void testGetTempPath() {

0 commit comments

Comments
 (0)