13514
|
1 /*
|
|
2 * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
|
|
3 * code is released under a tri EPL/GPL/LGPL license. You can use it,
|
|
4 * redistribute it and/or modify it under the terms of the:
|
|
5 *
|
|
6 * Eclipse Public License version 1.0
|
|
7 * GNU General Public License version 2
|
|
8 * GNU Lesser General Public License version 2.1
|
|
9 */
|
|
10 package com.oracle.truffle.ruby.runtime.core;
|
|
11
|
|
12 import java.util.*;
|
|
13 import java.util.concurrent.*;
|
|
14
|
|
15 import com.oracle.truffle.ruby.runtime.objects.*;
|
|
16 import com.oracle.truffle.ruby.runtime.subsystems.*;
|
|
17
|
|
18 /**
|
|
19 * Represents the Ruby {@code Thread} class. Implemented using Java threads, but note that there is
|
|
20 * not a one-to-one mapping between Ruby threads and Java threads - specifically in combination with
|
|
21 * fibers as they are currently implemented as their own Java threads.
|
|
22 */
|
|
23 public class RubyThread extends RubyObject {
|
|
24
|
|
25 /**
|
|
26 * The class from which we create the object that is {@code Thread}. A subclass of
|
|
27 * {@link RubyClass} so that we can override {@link #newInstance} and allocate a
|
|
28 * {@link RubyThread} rather than a normal {@link RubyBasicObject}.
|
|
29 */
|
|
30 public static class RubyThreadClass extends RubyClass {
|
|
31
|
|
32 public RubyThreadClass(RubyClass objectClass) {
|
|
33 super(null, objectClass, "Thread");
|
|
34 }
|
|
35
|
|
36 @Override
|
|
37 public RubyBasicObject newInstance() {
|
|
38 return new RubyThread(this, getContext().getThreadManager());
|
|
39 }
|
|
40
|
|
41 }
|
|
42
|
|
43 private final ThreadManager manager;
|
|
44
|
|
45 private final CountDownLatch finished = new CountDownLatch(1);
|
|
46
|
|
47 private final int hashCode = new Random().nextInt();
|
|
48
|
|
49 public RubyThread(RubyClass rubyClass, ThreadManager manager) {
|
|
50 super(rubyClass);
|
|
51 this.manager = manager;
|
|
52 }
|
|
53
|
|
54 public void initialize(RubyProc block) {
|
|
55 final RubyProc finalBlock = block;
|
|
56
|
|
57 initialize(new Runnable() {
|
|
58
|
|
59 @Override
|
|
60 public void run() {
|
|
61 finalBlock.call(null);
|
|
62 }
|
|
63
|
|
64 });
|
|
65 }
|
|
66
|
|
67 public void initialize(Runnable runnable) {
|
|
68 final RubyThread finalThread = this;
|
|
69 final Runnable finalRunnable = runnable;
|
|
70
|
|
71 new Thread(new Runnable() {
|
|
72
|
|
73 @Override
|
|
74 public void run() {
|
|
75 finalThread.manager.registerThread(finalThread);
|
|
76 finalThread.manager.enterGlobalLock(finalThread);
|
|
77
|
|
78 try {
|
|
79 finalRunnable.run();
|
|
80 } finally {
|
|
81 finalThread.manager.leaveGlobalLock();
|
|
82 finalThread.manager.unregisterThread(finalThread);
|
|
83 finalThread.finished.countDown();
|
|
84 }
|
|
85 }
|
|
86
|
|
87 }).start();
|
|
88 }
|
|
89
|
|
90 @Override
|
|
91 public int hashCode() {
|
|
92 return hashCode;
|
|
93 }
|
|
94
|
|
95 public void shutdown() {
|
|
96 }
|
|
97
|
|
98 public void join() {
|
|
99 final RubyThread runningThread = getRubyClass().getContext().getThreadManager().leaveGlobalLock();
|
|
100
|
|
101 try {
|
|
102 while (true) {
|
|
103 try {
|
|
104 finished.await();
|
|
105 break;
|
|
106 } catch (InterruptedException e) {
|
|
107 // Await again
|
|
108 }
|
|
109 }
|
|
110 } finally {
|
|
111 runningThread.manager.enterGlobalLock(runningThread);
|
|
112 }
|
|
113 }
|
|
114
|
|
115 }
|