-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcommon.h
More file actions
809 lines (566 loc) · 22.5 KB
/
common.h
File metadata and controls
809 lines (566 loc) · 22.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
// Header guard
#ifndef COMMON_H
#define COMMON_H
// Header files
using namespace std;
// Constants
// Solution size
#define SOLUTION_SIZE 42
// Number of edges
#define NUMBER_OF_EDGES (static_cast<uint64_t>(1) << EDGE_BITS)
// Max slean trimming parts
#define MAX_SLEAN_TRIMMING_PARTS 16
// Min local RAM kilobytes
#define MIN_LOCAL_RAM_KILOBYTES 32
// Checks
// Throw error if host's byte order isn't little endian
static_assert(endian::native == endian::little, "Host's byte order isn't little endian");
// Throw error if host isn't at least 64-bit
static_assert(sizeof(size_t) >= sizeof(uint64_t), "Host isn't at least 64-bit");
// Throw error if edge bits is invalid
static_assert(EDGE_BITS >= 10 && EDGE_BITS <= 32, "Edge bits is outside of the accepted range");
// Throw error if trimming rounds is invalid (Number of edges after a pair of trimming rounds ≈ NUMBER_OF_EDGES / (pow(roundNumber / 2 + 1, 2) + 2))
static_assert(TRIMMING_ROUNDS >= 0 && TRIMMING_ROUNDS <= 1000, "Trimming rounds is outside of the accepted range");
static_assert(static_cast<double>(NUMBER_OF_EDGES) / (((TRIMMING_ROUNDS + 1) / 2 + 1) * ((TRIMMING_ROUNDS + 1) / 2 + 1) + 2) >= SOLUTION_SIZE, "Trimming rounds is too high for the number of edge bits");
// Throw error if slean trimming parts is invalid
static_assert(SLEAN_TRIMMING_PARTS >= 2 && SLEAN_TRIMMING_PARTS <= MAX_SLEAN_TRIMMING_PARTS, "Slean trimming parts is outside of the accepted range");
static_assert(has_single_bit(static_cast<unsigned int>(SLEAN_TRIMMING_PARTS)), "Slean trimming parts isn't a power of two");
// Throw error if local RAM kilobytes is invalid
static_assert(LOCAL_RAM_KILOBYTES >= MIN_LOCAL_RAM_KILOBYTES && LOCAL_RAM_KILOBYTES <= 256, "Local RAM kilobytes is outside of the accepted range");
static_assert(has_single_bit(static_cast<unsigned int>(LOCAL_RAM_KILOBYTES)), "Local RAM kilobytes isn't a power of two");
// Throw error if stratum server number of mining algorithms is invalid
static_assert(STRATUM_SERVER_NUMBER_OF_MINING_ALGORITHMS >= 1 && STRATUM_SERVER_NUMBER_OF_MINING_ALGORITHMS <= 10, "Stratum server number of mining algorithms is outside of the accepted range");
// Throw error if the size of a vector of a type isn't the same as the size of an array of that type
static_assert(sizeof(uint64_t __attribute__((vector_size(8)))) == sizeof(uint64_t[1]), "Vector vs array size mismatch");
// Check if using an Apple device and not using OpenCL
#if defined __APPLE__ && !defined USE_OPENCL
// Throw error if the size of a vector of a type isn't the same as the size of a Metal vector of that type
static_assert(sizeof(uint64_t __attribute__((vector_size(8 * 4)))) == sizeof(uint64_t[4]), "Vector vs Metal vector size mismatch");
// Throw error if the size of a Metal vector type isn't double the size of a Metal vector of twice that type
static_assert(sizeof(uint32_t) == sizeof(uint32_t[2]) / 2 && sizeof(uint32_t[2]) == sizeof(uint32_t[4]) / 2, "Metal vector size mismatch");
// Otherwise
#else
// Throw error if the size of a vector of a type isn't the same as the size of an OpenCL vector of that type
static_assert(sizeof(uint64_t __attribute__((vector_size(8 * 4)))) == sizeof(cl_ulong4), "Vector vs OpenCL vector size mismatch");
// Throw error if the size of an OpenCL vector type isn't double the size of an OpenCL vector of twice that type
static_assert(sizeof(cl_uint) == sizeof(cl_uint2) / 2 && sizeof(cl_uint2) == sizeof(cl_uint4) / 2, "OpenCL vector size mismatch");
#endif
// Constants
// Bits in a byte
#define BITS_IN_A_BYTE 8
// Bytes in a kilobyte
#define BYTES_IN_A_KILOBYTE 1024
// Kilobytes in a megabyte
#define KILOBYTES_IN_A_MEGABYTE 1024
// Megabytes in a gigabyte
#define MEGABYTES_IN_A_GIGABYTE 1024
// Decimal number base
#define DECIMAL_NUMBER_BASE 10
// Bitmap unit width
#define BITMAP_UNIT_WIDTH (sizeof(uint64_t) * BITS_IN_A_BYTE)
// Edges bitmap size
#define EDGES_BITMAP_SIZE (NUMBER_OF_EDGES / BITMAP_UNIT_WIDTH)
// Node mask
#define NODE_MASK (NUMBER_OF_EDGES - 1)
// BLAKE2b hash size
#define BLAKE2B_HASH_SIZE 32
// Secp256k1 private key size
#define SECP256K1_PRIVATE_KEY_SIZE 32
// Stratum server mining algorithm size
#define STRATUM_SERVER_MINING_ALGORITHM_SIZE (sizeof(uint8_t) + sizeof(uint64_t))
// Check if stratum server uses one mining algorithm
#if STRATUM_SERVER_NUMBER_OF_MINING_ALGORITHMS == 1
// Header size
#define HEADER_SIZE (sizeof(uint16_t) + sizeof(uint64_t) + sizeof(int64_t) + BLAKE2B_HASH_SIZE + BLAKE2B_HASH_SIZE + BLAKE2B_HASH_SIZE + BLAKE2B_HASH_SIZE + BLAKE2B_HASH_SIZE + SECP256K1_PRIVATE_KEY_SIZE + sizeof(uint64_t) + sizeof(uint64_t) + sizeof(uint64_t) + sizeof(uint32_t))
// Otherwise
#else
// Header size
#define HEADER_SIZE (sizeof(uint16_t) + sizeof(uint64_t) + sizeof(int64_t) + BLAKE2B_HASH_SIZE + BLAKE2B_HASH_SIZE + BLAKE2B_HASH_SIZE + BLAKE2B_HASH_SIZE + BLAKE2B_HASH_SIZE + SECP256K1_PRIVATE_KEY_SIZE + sizeof(uint64_t) + sizeof(uint64_t) + sizeof(uint64_t) + STRATUM_SERVER_MINING_ALGORITHM_SIZE * STRATUM_SERVER_NUMBER_OF_MINING_ALGORITHMS + sizeof(uint32_t))
#endif
// Check if there's no trimming rounds
#if TRIMMING_ROUNDS == 0
// Max number of edges after trimming
#define MAX_NUMBER_OF_EDGES_AFTER_TRIMMING NUMBER_OF_EDGES
// Otherwise
#else
// Max number of edges after trimming
#define MAX_NUMBER_OF_EDGES_AFTER_TRIMMING ceilingConstantExpression(static_cast<double>(NUMBER_OF_EDGES) / (((TRIMMING_ROUNDS + 1) / 2) * ((TRIMMING_ROUNDS + 1) / 2) + 2) - 1)
#endif
// Edge number of components
#define EDGE_NUMBER_OF_COMPONENTS 3
// Milliseconds in a second
#define MILLISECONDS_IN_A_SECOND 1000
// All devices
#define ALL_DEVICES 0
// GNOME inhibit suspending session
#define GNOME_INHIBIT_SUSPENDING_SESSION (1 << 2)
// Classes
// Prevent sleep
class PreventSleep final {
// Public
public:
// Constructor
inline explicit PreventSleep() noexcept;
// Destructor
inline ~PreventSleep() noexcept;
// Bool operator
inline explicit operator bool() const noexcept;
// Did prevent sleep
inline bool didPreventSleep() const noexcept;
// Private
private:
// Fatal error occurred
bool fatalErrorOccurred;
// Check if using an Apple device
#ifdef __APPLE__
// Check if using macOS
#if TARGET_OS_OSX == 1
// Assertion ID
IOPMAssertionID assertionID;
#endif
// Otherwise check if not using Windows and Android
#elif !defined _WIN32 && !defined __ANDROID__
// Allow sleep message
unique_ptr<DBusMessage, decltype(&dbus_message_unref)> allowSleepMessage;
#endif
};
// Check if not using an Apple device or using OpenCL
#if !defined __APPLE__ || defined USE_OPENCL
// Event class
class Event final {
// Public
public:
// Constructor
inline explicit Event() noexcept;
// Destructor
inline ~Event() noexcept;
// Get address
inline cl_event *getAddress() noexcept;
// Get
inline const cl_event &get() const noexcept;
// Free
inline void free() noexcept;
// Private
private:
// Event
cl_event event;
};
#endif
// Check if Windows
#ifdef _WIN32
// Windows socket class
class WindowsSocket final {
// Public
public:
// Constructor
inline explicit WindowsSocket() noexcept;
// Destructor
inline ~WindowsSocket() noexcept;
// Bool operator
inline explicit operator bool() const noexcept;
// Private
private:
// Major version
static const BYTE MAJOR_VERSION;
// Minor version
static const BYTE MINOR_VERSION;
// Fatal error occurred
bool fatalErrorOccurred;
};
#endif
// Constants
// Check if Windows
#ifdef _WIN32
// Windows socket major version
const BYTE WindowsSocket::MAJOR_VERSION = 2;
// Windows socket minor version
const BYTE WindowsSocket::MINOR_VERSION = 2;
#endif
// Function prototypes
// Ceiling constant expression
static inline constexpr unsigned int ceilingConstantExpression(const double value) noexcept;
// Bit ceiling constant expression
static inline constexpr unsigned int bitCeilingConstantExpression(const unsigned int value) noexcept;
// Unmove
template<typename ValueType> static inline ValueType &unmove(ValueType &&value) noexcept;
// Set thread priority and affinity
static inline bool setThreadPriorityAndAffinity(const unsigned int threadIndex) noexcept;
// Securely clear
static inline void securelyClear(void *data, const size_t length) noexcept;
// Get number of CPU cores
static inline unsigned int getNumberOfCpuCores() noexcept;
// Get number of high performance CPU cores
static inline unsigned int getNumberOfHighPerformanceCpuCores() noexcept;
// Supporting function implementation
// Prevent sleep constructor
PreventSleep::PreventSleep() noexcept :
// Set fatal error occurred to false
fatalErrorOccurred(false)
// Check if using Windows
#ifdef _WIN32
{
// Check if preventing sleep failed
if(!SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED)) {
// Set fatal error occurred to true
fatalErrorOccurred = true;
}
// Otherwise check if using an Apple device
#elif defined __APPLE__
{
// Check if using macOS
#if TARGET_OS_OSX == 1
// Check if preventing sleep failed
if(IOPMAssertionCreateWithName(kIOPMAssertionTypePreventUserIdleSystemSleep, kIOPMAssertionLevelOn, CFSTR(TO_STRING(NAME) " is running"), &assertionID) != kIOReturnSuccess) {
// Set fatal error occurred to true
fatalErrorOccurred = true;
}
#endif
// Otherwise check if not using Android
#elif !defined __ANDROID__
// Set allow sleep to nothing
, allowSleepMessage(nullptr, dbus_message_unref)
{
// Check if connecting to the session bus was successful
DBusConnection *connection = dbus_bus_get(DBUS_BUS_SESSION, nullptr);
if(connection) {
// Set application identifier and reason
const char *applicationIdentifier = TO_STRING(NAME);
const char *reason = TO_STRING(NAME) " is running";
// Check if creating message to prevent sleep for GNOME-compliant environments was successful
unique_ptr<DBusMessage, decltype(&dbus_message_unref)> message(dbus_message_new_method_call("org.gnome.SessionManager", "/org/gnome/SessionManager", "org.gnome.SessionManager", "Inhibit"), dbus_message_unref);
if(message) {
// Check if setting message's application identifier, toplevel X window identifier, reason, and flags arguments was successful
if(dbus_message_append_args(message.get(), DBUS_TYPE_STRING, &applicationIdentifier, DBUS_TYPE_UINT32, &unmove(static_cast<dbus_uint32_t>(0)), DBUS_TYPE_STRING, &reason, DBUS_TYPE_UINT32, &unmove(static_cast<dbus_uint32_t>(GNOME_INHIBIT_SUSPENDING_SESSION)), DBUS_TYPE_INVALID)) {
// Check if getting message's reply was successful
const unique_ptr<DBusMessage, decltype(&dbus_message_unref)> reply(dbus_connection_send_with_reply_and_block(connection, message.get(), DBUS_TIMEOUT_USE_DEFAULT, nullptr), dbus_message_unref);
if(reply) {
// Check if getting reply's inhibit cookie was successful
dbus_uint32_t inhibitCookie;
if(dbus_message_get_args(reply.get(), nullptr, DBUS_TYPE_UINT32, &inhibitCookie, DBUS_TYPE_INVALID)) {
// Check if creating message to allow sleep was successful
allowSleepMessage = unique_ptr<DBusMessage, decltype(&dbus_message_unref)>(dbus_message_new_method_call("org.gnome.SessionManager", "/org/gnome/SessionManager", "org.gnome.SessionManager", "Uninhibit"), dbus_message_unref);
if(allowSleepMessage) {
// Check if setting allow sleep message's inhibit cookit argument failed
if(!dbus_message_append_args(allowSleepMessage.get(), DBUS_TYPE_UINT32, &inhibitCookie, DBUS_TYPE_INVALID)) {
// Free allow sleep message
allowSleepMessage.reset();
}
// Otherwise
else {
// Return
return;
}
}
}
}
}
}
// Check if creating message to prevent sleep for Freedesktop-compliant environments was successful
message = unique_ptr<DBusMessage, decltype(&dbus_message_unref)>(dbus_message_new_method_call("org.freedesktop.PowerManagement", "/org/freedesktop/PowerManagement/Inhibit", "org.freedesktop.PowerManagement", "Inhibit"), dbus_message_unref);
if(message) {
// Check if setting message's application identifier and reason arguments was successful
if(dbus_message_append_args(message.get(), DBUS_TYPE_STRING, &applicationIdentifier, DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID)) {
// Check if getting message's reply was successful
const unique_ptr<DBusMessage, decltype(&dbus_message_unref)> reply(dbus_connection_send_with_reply_and_block(connection, message.get(), DBUS_TIMEOUT_USE_DEFAULT, nullptr), dbus_message_unref);
if(reply) {
// Check if getting reply's inhibit cookie was successful
dbus_uint32_t inhibitCookie;
if(dbus_message_get_args(reply.get(), nullptr, DBUS_TYPE_UINT32, &inhibitCookie, DBUS_TYPE_INVALID)) {
// Check if creating message to allow sleep was successful
allowSleepMessage = unique_ptr<DBusMessage, decltype(&dbus_message_unref)>(dbus_message_new_method_call("org.freedesktop.PowerManagement", "/org/freedesktop/PowerManagement/Inhibit", "org.freedesktop.PowerManagement", "Uninhibit"), dbus_message_unref);
if(allowSleepMessage) {
// Check if setting allow sleep message's inhibit cookit argument failed
if(!dbus_message_append_args(allowSleepMessage.get(), DBUS_TYPE_UINT32, &inhibitCookie, DBUS_TYPE_INVALID)) {
// Free allow sleep message
allowSleepMessage.reset();
}
// Otherwise
else {
// Return
return;
}
}
}
}
}
}
}
// Otherwise
#else
{
#endif
}
// Prevent sleep destructor
PreventSleep::~PreventSleep() noexcept {
// Check if a fatal error didn't occur
if(!fatalErrorOccurred) {
// Check if using Windows
#ifdef _WIN32
// Allow sleep
SetThreadExecutionState(ES_CONTINUOUS);
// Otherwise check if using an Apple device
#elif defined __APPLE__
// Check if using macOS
#if TARGET_OS_OSX == 1
// Allow sleep
IOPMAssertionRelease(assertionID);
#endif
// Otherwise check if not using Android
#elif !defined __ANDROID__
// Check if allow sleep message exists
if(allowSleepMessage) {
// Check if connecting to the session bus was successful
DBusConnection *connection = dbus_bus_get(DBUS_BUS_SESSION, nullptr);
if(connection) {
// Get allow sleep message's reply
unique_ptr<DBusMessage, decltype(&dbus_message_unref)>(dbus_connection_send_with_reply_and_block(connection, allowSleepMessage.get(), DBUS_TIMEOUT_USE_DEFAULT, nullptr), dbus_message_unref);
}
}
#endif
}
}
// Prevent sleep bool operator
PreventSleep::operator bool() const noexcept {
// Return if a fatal error didn't occurred
return !fatalErrorOccurred;
}
// Prevent sleep did prevent sleep
bool PreventSleep::didPreventSleep() const noexcept {
// Check if using Windows
#ifdef _WIN32
// Return true;
return true;
// Otherwise check if using an Apple device
#elif defined __APPLE__
// Check if using macOS
#if TARGET_OS_OSX == 1
// Return true;
return true;
// Otherwise
#else
// Return false
return false;
#endif
// Otherwise check if not using Android
#elif !defined __ANDROID__
// Return if allow sleep message exists
return allowSleepMessage.get();
// Otherwise
#else
// Return false
return false;
#endif
}
// Check if not using an Apple device or using OpenCL
#if !defined __APPLE__ || defined USE_OPENCL
// Event constructor
Event::Event() noexcept :
// Set event to nothing
event(nullptr)
{
}
// Event destructor
Event::~Event() noexcept {
// Wait for event to finish
clWaitForEvents(1, &event);
// Free event
clReleaseEvent(event);
}
// Event get address
cl_event *Event::getAddress() noexcept {
// Return event's address
return &event;
}
// Event get
const cl_event &Event::get() const noexcept {
// Return event
return event;
}
// Event free
void Event::free() noexcept {
// Free event
clReleaseEvent(event);
// Set event to nothing
event = nullptr;
}
#endif
// Check if Windows
#ifdef _WIN32
// Windows socket constructor
WindowsSocket::WindowsSocket() noexcept :
// Set fatal error occurred to false
fatalErrorOccurred(false)
{
// Check if initializing Windows socket failed
WSAData windowsSocketData;
if(WSAStartup(MAKEWORD(WindowsSocket::MAJOR_VERSION, WindowsSocket::MINOR_VERSION), &windowsSocketData)) {
// Set fatal error occurred to true
fatalErrorOccurred = true;
}
}
// Windows socket destructor
WindowsSocket::~WindowsSocket() noexcept {
// Check if a fatal error didn't occur
if(!fatalErrorOccurred) {
// Clean up Windows socket
WSACleanup();
}
}
// Windows socket bool operator
WindowsSocket::operator bool() const noexcept {
// Return if a fatal error didn't occurred
return !fatalErrorOccurred;
}
#endif
// Ceiling constant expression
constexpr unsigned int ceilingConstantExpression(const double value) noexcept {
// Get value as an integer
const unsigned int integerValue = static_cast<unsigned int>(value);
// Return one more than the integer if it's less than the value
return (integerValue < value) ? integerValue + 1 : integerValue;
}
// Bit ceiling constant expression
constexpr unsigned int bitCeilingConstantExpression(const unsigned int value) noexcept {
// Return power of two not less than value
return 1 << (sizeof(value) * BITS_IN_A_BYTE - __builtin_clz(value - 1));
}
// Unmove
template<typename ValueType> ValueType &unmove(ValueType &&value) noexcept {
// Return value as an lvalue
return static_cast<ValueType &>(value);
}
// Check if using Windows
#ifdef _WIN32
// Set thread priority and affinity
bool setThreadPriorityAndAffinity(__attribute__((unused)) const unsigned int threadIndex) noexcept {
// Otherwise
#else
// Set thread priority and affinity
bool setThreadPriorityAndAffinity(const unsigned int threadIndex) noexcept {
#endif
// Check if using Windows
#ifdef _WIN32
// Check if setting thread's scheduling priority to max failed
if(!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL)) {
// Return false
return false;
}
// Check if setting thread's CPU affinity to its own core failed (This makes the program slower on Windows, so commenting it out)
/*if(!SetThreadAffinityMask(GetCurrentThread(), static_cast<uint64_t>(1) << threadIndex)) {
// Return false
return false;
}*/
// Otherwise check if using an Apple device
#elif defined __APPLE__
// Check if setting thread's scheduling priority to max failed
if(pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0)) {
// Return false
return false;
}
// Check if setting thread's CPU affinity to its own core failed
thread_affinity_policy_data_t affinityPolicy = {
// Affinity tag
.affinity_tag = static_cast<integer_t>(threadIndex + 1)
};
const kern_return_t result = thread_policy_set(pthread_mach_thread_np(pthread_self()), THREAD_AFFINITY_POLICY, reinterpret_cast<thread_policy_t>(&affinityPolicy), THREAD_AFFINITY_POLICY_COUNT);
if(result != KERN_SUCCESS && result != KERN_NOT_SUPPORTED) {
// Return false
return false;
}
// Otherwise
#else
// Check if getting thread's scheduling policy failed
int schedulingPolicy;
sched_param schedulingParameters;
if(pthread_getschedparam(pthread_self(), &schedulingPolicy, &schedulingParameters)) {
// Return false
return false;
}
// Check if getting the max priority for the thread's scheduling policy failed
schedulingParameters.sched_priority = sched_get_priority_max(schedulingPolicy);
if(schedulingParameters.sched_priority == -1) {
// Return false
return false;
}
// Check if setting thread's scheduling priority to max failed
if(pthread_setschedparam(pthread_self(), schedulingPolicy, &schedulingParameters)) {
// Return false
return false;
}
// Check if using Android and API level is less than 36
cpu_set_t cpuSet;
CPU_ZERO(&cpuSet);
CPU_SET(threadIndex, &cpuSet);
#if defined __ANDROID__ && __ANDROID_MIN_SDK_VERSION__ < 36
// Check if setting thread's CPU affinity to its own core failed
if(sched_setaffinity(pthread_gettid_np(pthread_self()), sizeof(cpuSet), &cpuSet)) {
// Otherwise
#else
// Check if setting thread's CPU affinity to its own core failed
if(pthread_setaffinity_np(pthread_self(), sizeof(cpuSet), &cpuSet)) {
#endif
// Return false
return false;
}
#endif
// Return true
return true;
}
// Securely clear
void securelyClear(void *data, const size_t length) noexcept {
// Check if using Windows
#ifdef _WIN32
// Securely clear data
SecureZeroMemory(data, length);
// Otherwise check if using an Apple device
#elif defined __APPLE__
// Securely clear data
memset_s(data, length, 0, length);
// Otherwise check if using Android
#elif defined __ANDROID__
// Check if API level is at least 34
#if __ANDROID_MIN_SDK_VERSION__ >= 34
// Securely clear data
memset_explicit(data, 0, length);
// Otherwise
#else
// Securely clear data
memset(data, 0, length);
#endif
// Otherwise
#else
// Securely clear data
explicit_bzero(data, length);
#endif
}
// Get number of CPU cores
unsigned int getNumberOfCpuCores() noexcept {
// Check if using an Apple device
#if __APPLE__
// Check if getting the number of CPU cores was successful
int32_t numberOfCpuCores;
size_t numberOfCpuCoresSize = sizeof(numberOfCpuCores);
if(!sysctlbyname("hw.logicalcpu", &numberOfCpuCores, &numberOfCpuCoresSize, nullptr, 0)) {
// Return number of CPU cores
return max(numberOfCpuCores, 1);
}
#endif
// Return number of CPU cores
return max(thread::hardware_concurrency(), static_cast<unsigned int>(1));
}
// Get number of high performance CPU cores
unsigned int getNumberOfHighPerformanceCpuCores() noexcept {
// Check if using an Apple device
#if __APPLE__
// Check if getting the number of high performance CPU cores was successful
int32_t numberOfHighPerformanceCpuCores;
size_t numberOfHighPerformanceCpuCoresSize = sizeof(numberOfHighPerformanceCpuCores);
if(!sysctlbyname("hw.perflevel0.logicalcpu", &numberOfHighPerformanceCpuCores, &numberOfHighPerformanceCpuCoresSize, nullptr, 0)) {
// Return number of high performance CPU cores
return max(numberOfHighPerformanceCpuCores, 1);
}
#endif
// Return number of CPU cores
return max(thread::hardware_concurrency(), static_cast<unsigned int>(1));
}
#endif