Skip to content

Commit 60f7656

Browse files
committed
add custom task threads via os api
1 parent 19905c0 commit 60f7656

3 files changed

Lines changed: 126 additions & 0 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.github.elebras1.flecs.examples.components;
2+
3+
4+
import com.github.elebras1.flecs.*;
5+
import com.github.elebras1.flecs.util.FlecsConstants;
6+
7+
import java.util.Map;
8+
import java.util.concurrent.ConcurrentHashMap;
9+
import java.util.concurrent.ExecutorService;
10+
import java.util.concurrent.Executors;
11+
import java.util.concurrent.Future;
12+
import java.util.concurrent.atomic.AtomicLong;
13+
14+
public class TaskThreadExample {
15+
16+
private static final int NUMBER_THREADS = 4;
17+
18+
public static void main(String[] args) {
19+
ExecutorService executor = Executors.newFixedThreadPool(NUMBER_THREADS);
20+
Map<Long, Future<?>> futures = new ConcurrentHashMap<>();
21+
AtomicLong counter = new AtomicLong();
22+
23+
OsApi osApi = new OsApi();
24+
osApi.taskNew(task -> {
25+
long id = counter.incrementAndGet();
26+
futures.put(id, executor.submit(task));
27+
return id;
28+
})
29+
.taskJoin(id -> {
30+
try {
31+
futures.remove(id).get();
32+
} catch (Exception e) {
33+
Thread.currentThread().interrupt();
34+
}
35+
})
36+
.set();
37+
38+
try (World world = new World()) {
39+
world.setTaskThreads(NUMBER_THREADS);
40+
world.component(Health.class);
41+
42+
for(int i = 0; i < 100_000; i++) {
43+
EntityView entity = world.obtainEntityView(world.entity());
44+
entity.set(Health.class, (HealthView health) -> health.value(100));
45+
}
46+
47+
world.system().with(Health.class).kind(FlecsConstants.EcsOnUpdate).multiThreaded().iter(iter -> {
48+
Field<Health> healthField = iter.field(Health.class, 0);
49+
for(int i = 0; i < iter.count(); i++) {
50+
HealthView health = healthField.getMutView(i);
51+
health.value(health.value() - 1);
52+
}
53+
});
54+
55+
for(int i = 0; i < 1000; i++) {
56+
world.progress();
57+
}
58+
59+
executor.close();
60+
}
61+
62+
}
63+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.github.elebras1.flecs;
2+
3+
import com.github.elebras1.flecs.util.internal.FlecsLoader;
4+
5+
import java.lang.foreign.Arena;
6+
import java.lang.foreign.MemorySegment;
7+
8+
public class OsApi implements AutoCloseable {
9+
private final Arena arena;
10+
private final MemorySegment nativeOsApi;
11+
12+
static {
13+
FlecsLoader.load();
14+
}
15+
16+
@FunctionalInterface
17+
public interface TaskNewCallback {
18+
long run(Runnable task);
19+
}
20+
21+
@FunctionalInterface
22+
public interface TaskJoinCallback {
23+
void run(long threadId);
24+
}
25+
26+
public OsApi() {
27+
this.arena = Arena.ofConfined();
28+
flecs_h.ecs_os_set_api_defaults();
29+
this.nativeOsApi = flecs_h.ecs_os_get_api(this.arena);
30+
}
31+
32+
public OsApi taskNew(TaskNewCallback callback) {
33+
MemorySegment nativeCallback = ecs_os_api_thread_new_t.allocate((cb, arg) ->
34+
callback.run(() -> ecs_os_thread_callback_t.invoke(cb, arg)), this.arena);
35+
ecs_os_api_t.task_new_(this.nativeOsApi, nativeCallback);
36+
return this;
37+
}
38+
39+
public OsApi taskJoin(TaskJoinCallback callback) {
40+
MemorySegment nativeCallback = ecs_os_api_thread_join_t.allocate((threadId) -> {
41+
callback.run(threadId);
42+
return MemorySegment.NULL;
43+
}, this.arena);
44+
ecs_os_api_t.task_join_(this.nativeOsApi, nativeCallback);
45+
return this;
46+
}
47+
48+
public void set() {
49+
flecs_h.ecs_os_set_api(this.nativeOsApi);
50+
}
51+
52+
@Override
53+
public void close() throws Exception {
54+
this.arena.close();
55+
}
56+
}

src/main/java/com/github/elebras1/flecs/World.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,13 @@ public void setThreads(int threads) {
412412
this.resetStages();
413413
}
414414

415+
public void setTaskThreads(int taskThreads) {
416+
this.checkClosed();
417+
flecs_h.ecs_set_task_threads(this.nativeWorld, taskThreads);
418+
419+
this.resetStages();
420+
}
421+
415422
public void setPipeline(long pipelineId) {
416423
this.checkClosed();
417424
flecs_h.ecs_set_pipeline(this.nativeWorld, pipelineId);

0 commit comments

Comments
 (0)