Skip to content

Commit fe44f26

Browse files
committed
[umf] add windows support to critnib
Implement locks using C++ std::mutex and atomics by using Interlocked* functions and calling _ReadWriteBarrier
1 parent c8a2d34 commit fe44f26

File tree

6 files changed

+154
-45
lines changed

6 files changed

+154
-45
lines changed

source/common/unified_malloc_framework/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ set(UMF_SOURCES
1111
src/critnib/critnib.c
1212
)
1313

14-
if (MSVC)
15-
set(UMF_SOURCES ${UMF_SOURCES} src/memory_tracker_windows.cpp)
14+
if(MSVC)
15+
set(UMF_SOURCES ${UMF_SOURCES} src/utils/utils_windows.cpp src/memory_tracker_windows.cpp)
16+
else()
17+
set(UMF_SOURCES ${UMF_SOURCES} src/utils/utils_posix.c)
1618
endif()
1719

1820
if(UMF_BUILD_SHARED_LIBRARY)

source/common/unified_malloc_framework/src/critnib/critnib.c

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@
5858
#include <stdbool.h>
5959
#include <stddef.h>
6060

61+
#include "../utils/utils.h"
6162
#include "critnib.h"
62-
#include "pmdk-compat.h"
6363

6464
/*
6565
* A node that has been deleted is left untouched for this many delete
@@ -126,25 +126,25 @@ struct critnib {
126126

127127
uint64_t remove_count;
128128

129-
os_mutex_t mutex; /* writes/removes */
129+
struct os_mutex_t *mutex; /* writes/removes */
130130
};
131131

132132
/*
133133
* atomic load
134134
*/
135135
static void load(void *src, void *dst) {
136-
__atomic_load((word *)src, (word *)dst, memory_order_acquire);
136+
util_atomic_load_acquire((word *)src, (word *)dst);
137137
}
138138

139139
static void load64(uint64_t *src, uint64_t *dst) {
140-
__atomic_load(src, dst, memory_order_acquire);
140+
util_atomic_load_acquire(src, dst);
141141
}
142142

143143
/*
144144
* atomic store
145145
*/
146146
static void store(void *dst, void *src) {
147-
__atomic_store_n((word *)dst, (word)src, memory_order_release);
147+
util_atomic_store_release((word *)dst, (word)src);
148148
}
149149

150150
/*
@@ -181,7 +181,11 @@ struct critnib *critnib_new(void) {
181181
return NULL;
182182
}
183183

184-
util_mutex_init(&c->mutex);
184+
c->mutex = util_mutex_create();
185+
if (!c->mutex) {
186+
free(c);
187+
return NULL;
188+
}
185189

186190
VALGRIND_HG_DRD_DISABLE_CHECKING(&c->root, sizeof(c->root));
187191
VALGRIND_HG_DRD_DISABLE_CHECKING(&c->remove_count, sizeof(c->remove_count));
@@ -214,7 +218,7 @@ void critnib_delete(struct critnib *c) {
214218
delete_node(c->root);
215219
}
216220

217-
util_mutex_destroy(&c->mutex);
221+
util_mutex_destroy(c->mutex);
218222

219223
for (struct critnib_node *m = c->deleted_node; m;) {
220224
struct critnib_node *mm = m->child[0];
@@ -313,11 +317,11 @@ static struct critnib_leaf *alloc_leaf(struct critnib *__restrict c) {
313317
* Takes a global write lock but doesn't stall any readers.
314318
*/
315319
int critnib_insert(struct critnib *c, word key, void *value, int update) {
316-
util_mutex_lock(&c->mutex);
320+
util_mutex_lock(c->mutex);
317321

318322
struct critnib_leaf *k = alloc_leaf(c);
319323
if (!k) {
320-
util_mutex_unlock(&c->mutex);
324+
util_mutex_unlock(c->mutex);
321325

322326
return ENOMEM;
323327
}
@@ -333,7 +337,7 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) {
333337
if (!n) {
334338
c->root = kn;
335339

336-
util_mutex_unlock(&c->mutex);
340+
util_mutex_unlock(c->mutex);
337341

338342
return 0;
339343
}
@@ -351,7 +355,7 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) {
351355
n = prev;
352356
store(&n->child[slice_index(key, n->shift)], kn);
353357

354-
util_mutex_unlock(&c->mutex);
358+
util_mutex_unlock(c->mutex);
355359

356360
return 0;
357361
}
@@ -365,10 +369,10 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) {
365369

366370
if (update) {
367371
to_leaf(n)->value = value;
368-
util_mutex_unlock(&c->mutex);
372+
util_mutex_unlock(c->mutex);
369373
return 0;
370374
} else {
371-
util_mutex_unlock(&c->mutex);
375+
util_mutex_unlock(c->mutex);
372376
return EEXIST;
373377
}
374378
}
@@ -380,7 +384,7 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) {
380384
if (!m) {
381385
free_leaf(c, to_leaf(kn));
382386

383-
util_mutex_unlock(&c->mutex);
387+
util_mutex_unlock(c->mutex);
384388

385389
return ENOMEM;
386390
}
@@ -396,7 +400,7 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) {
396400
m->path = key & path_mask(sh);
397401
store(parent, m);
398402

399-
util_mutex_unlock(&c->mutex);
403+
util_mutex_unlock(c->mutex);
400404

401405
return 0;
402406
}
@@ -408,15 +412,14 @@ void *critnib_remove(struct critnib *c, word key) {
408412
struct critnib_leaf *k;
409413
void *value = NULL;
410414

411-
util_mutex_lock(&c->mutex);
415+
util_mutex_lock(c->mutex);
412416

413417
struct critnib_node *n = c->root;
414418
if (!n) {
415419
goto not_found;
416420
}
417421

418-
word del = __atomic_fetch_add(&c->remove_count, 1, __ATOMIC_ACQ_REL) %
419-
DELETED_LIFE;
422+
word del = (util_atomic_increment(&c->remove_count) - 1) % DELETED_LIFE;
420423
free_node(c, c->pending_del_nodes[del]);
421424
free_leaf(c, c->pending_del_leaves[del]);
422425
c->pending_del_nodes[del] = NULL;
@@ -479,7 +482,7 @@ void *critnib_remove(struct critnib *c, word key) {
479482
c->pending_del_leaves[del] = k;
480483

481484
not_found:
482-
util_mutex_unlock(&c->mutex);
485+
util_mutex_unlock(c->mutex);
483486
return value;
484487
}
485488

@@ -802,9 +805,9 @@ static int iter(struct critnib_node *__restrict n, word min, word max,
802805
void critnib_iter(critnib *c, uintptr_t min, uintptr_t max,
803806
int (*func)(uintptr_t key, void *value, void *privdata),
804807
void *privdata) {
805-
util_mutex_lock(&c->mutex);
808+
util_mutex_lock(c->mutex);
806809
if (c->root) {
807810
iter(c->root, min, max, func, privdata);
808811
}
809-
util_mutex_unlock(&c->mutex);
812+
util_mutex_unlock(c->mutex);
810813
}

source/common/unified_malloc_framework/src/memory_tracker_windows.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
*
99
*/
1010

11+
#include "critnib/critnib.h"
12+
#include "memory_tracker.h"
13+
1114
#include <windows.h>
1215

1316
#if defined(UMF_SHARED_LIBRARY)
@@ -23,7 +26,7 @@ BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
2326
#else
2427
struct tracker_t {
2528
tracker_t() { map = critnib_new(); }
26-
~tracker_t() { critnib_remove(map); }
29+
~tracker_t() { critnib_delete(map); }
2730
critnib *map;
2831
};
2932
tracker_t TRACKER_INSTANCE;

source/common/unified_malloc_framework/src/critnib/pmdk-compat.h renamed to source/common/unified_malloc_framework/src/utils/utils.h

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,70 @@
88
*
99
*/
1010

11-
#include <pthread.h>
12-
#include <stdatomic.h>
11+
#include <stdio.h>
1312
#include <stdlib.h>
1413
#include <string.h>
14+
#if defined(_WIN32)
15+
#include <windows.h>
16+
#else
17+
#include <stdatomic.h>
18+
#endif
19+
20+
#ifdef __cplusplus
21+
extern "C" {
22+
#endif
23+
24+
struct os_mutex_t;
25+
26+
struct os_mutex_t *util_mutex_create(void);
27+
void util_mutex_destroy(struct os_mutex_t *mutex);
28+
int util_mutex_lock(struct os_mutex_t *mutex);
29+
int util_mutex_unlock(struct os_mutex_t *mutex);
30+
31+
#if defined(_WIN32)
32+
static __inline unsigned char util_lssb_index(long long value) {
33+
unsigned long ret;
34+
_BitScanForward64(&ret, value);
35+
return (unsigned char)ret;
36+
}
37+
static __inline unsigned char util_mssb_index(long long value) {
38+
unsigned long ret;
39+
_BitScanReverse64(&ret, value);
40+
return (unsigned char)ret;
41+
}
1542

16-
typedef pthread_mutex_t os_mutex_t;
43+
// There is no good way to do atomic_load on windows...
44+
#define util_atomic_load_acquire(object, dest) \
45+
do { \
46+
*dest = InterlockedOr64Acquire((LONG64 volatile *)dest, 0); \
47+
} while (0)
48+
49+
#define util_atomic_store_release(object, desired) \
50+
InterlockedExchange64((LONG64 volatile *)object, (LONG64)desired)
51+
#define util_atomic_increment(object) \
52+
InterlockedIncrement64((LONG64 volatile *)object)
53+
#else
54+
#define util_lssb_index(x) ((unsigned char)__builtin_ctzll(x))
55+
#define util_mssb_index(x) ((unsigned char)(63 - __builtin_clzll(x)))
56+
#define util_atomic_load_acquire(object, dest) \
57+
__atomic_load(object, dest, memory_order_acquire)
58+
#define util_atomic_store_release(object, desired) \
59+
__atomic_store_n(object, desired, memory_order_release)
60+
#define util_atomic_increment(object) \
61+
__atomic_add_fetch(object, 1, __ATOMIC_ACQ_REL)
62+
#endif
1763

1864
#define Malloc malloc
1965
#define Free free
2066

21-
static void *Zalloc(size_t s) {
67+
static inline void *Zalloc(size_t s) {
2268
void *m = Malloc(s);
2369
if (m) {
2470
memset(m, 0, s);
2571
}
2672
return m;
2773
}
2874

29-
#define util_mutex_init(x) pthread_mutex_init(x, NULL)
30-
#define util_mutex_destroy(x) pthread_mutex_destroy(x)
31-
#define util_mutex_lock(x) pthread_mutex_lock(x)
32-
#define util_mutex_unlock(x) pthread_mutex_unlock(x)
33-
#define util_lssb_index64(x) ((unsigned char)__builtin_ctzll(x))
34-
#define util_mssb_index64(x) ((unsigned char)(63 - __builtin_clzll(x)))
35-
#define util_lssb_index32(x) ((unsigned char)__builtin_ctzl(x))
36-
#define util_mssb_index32(x) ((unsigned char)(31 - __builtin_clzl(x)))
37-
#if __SIZEOF_LONG__ == 8
38-
#define util_lssb_index(x) util_lssb_index64(x)
39-
#define util_mssb_index(x) util_mssb_index64(x)
40-
#else
41-
#define util_lssb_index(x) util_lssb_index32(x)
42-
#define util_mssb_index(x) util_mssb_index32(x)
43-
#endif
44-
4575
#define NOFUNCTION \
4676
do \
4777
; \
@@ -53,7 +83,6 @@ static void *Zalloc(size_t s) {
5383
#define ASSERT(x) NOFUNCTION
5484
#define ASSERTne(x, y) ASSERT(x != y)
5585
#else
56-
#include <stdio.h>
5786
#define ASSERT(x) \
5887
do \
5988
if (!(x)) { \
@@ -76,3 +105,7 @@ static void *Zalloc(size_t s) {
76105
} \
77106
} while (0)
78107
#endif
108+
109+
#ifdef __cplusplus
110+
}
111+
#endif
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
*
3+
* Copyright (C) 2023 Intel Corporation
4+
*
5+
* Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions.
6+
* See LICENSE.TXT
7+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8+
*
9+
*/
10+
11+
#include <pthread.h>
12+
#include <stdlib.h>
13+
14+
#include "utils.h"
15+
16+
struct os_mutex_t *util_mutex_create() {
17+
pthread_mutex_t *mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
18+
int ret = pthread_mutex_init(mutex, NULL);
19+
return ret == 0 ? ((struct os_mutex_t *)mutex) : NULL;
20+
}
21+
22+
void util_mutex_destroy(struct os_mutex_t *m) {
23+
pthread_mutex_t *mutex = (pthread_mutex_t *)m;
24+
int ret = pthread_mutex_destroy(mutex);
25+
(void)ret; // TODO: add logging
26+
free(m);
27+
}
28+
29+
int util_mutex_lock(struct os_mutex_t *m) {
30+
return pthread_mutex_lock((pthread_mutex_t *)m);
31+
}
32+
33+
int util_mutex_unlock(struct os_mutex_t *m) {
34+
return pthread_mutex_unlock((pthread_mutex_t *)m);
35+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
*
3+
* Copyright (C) 2023 Intel Corporation
4+
*
5+
* Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions.
6+
* See LICENSE.TXT
7+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8+
*
9+
*/
10+
11+
#include <mutex>
12+
13+
#include "utils.h"
14+
15+
struct os_mutex_t *util_mutex_create(void) {
16+
return reinterpret_cast<struct os_mutex_t *>(new std::mutex);
17+
}
18+
19+
void util_mutex_destroy(struct os_mutex_t *mutex) {
20+
delete reinterpret_cast<std::mutex *>(mutex);
21+
}
22+
23+
int util_mutex_lock(struct os_mutex_t *mutex) try {
24+
reinterpret_cast<std::mutex *>(mutex)->lock();
25+
return 0;
26+
} catch (std::system_error &err) {
27+
return err.code().value();
28+
}
29+
30+
int util_mutex_unlock(struct os_mutex_t *mutex) {
31+
reinterpret_cast<std::mutex *>(mutex)->unlock();
32+
return 0;
33+
}

0 commit comments

Comments
 (0)