1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * java.lang.VMThread
19 */
20#include "Dalvik.h"
21#include "native/InternalNativePriv.h"
22
23
24/*
25 * static void create(Thread t, long stacksize)
26 *
27 * This is eventually called as a result of Thread.start().
28 *
29 * Throws an exception on failure.
30 */
31static void Dalvik_java_lang_VMThread_create(const u4* args, JValue* pResult)
32{
33    Object* threadObj = (Object*) args[0];
34    s8 stackSize = GET_ARG_LONG(args, 1);
35
36    dvmCreateInterpThread(threadObj, (int) stackSize);
37    RETURN_VOID();
38}
39
40/*
41 * static Thread currentThread()
42 */
43static void Dalvik_java_lang_VMThread_currentThread(const u4* args,
44    JValue* pResult)
45{
46    UNUSED_PARAMETER(args);
47
48    RETURN_PTR(dvmThreadSelf()->threadObj);
49}
50
51/*
52 * void getStatus()
53 *
54 * Gets the Thread status. Result is in VM terms, has to be mapped to
55 * Thread.State by interpreted code.
56 */
57static void Dalvik_java_lang_VMThread_getStatus(const u4* args, JValue* pResult)
58{
59    Object* thisPtr = (Object*) args[0];
60    Thread* thread;
61    int result;
62
63    dvmLockThreadList(NULL);
64    thread = dvmGetThreadFromThreadObject(thisPtr);
65    if (thread != NULL)
66        result = thread->status;
67    else
68        result = THREAD_ZOMBIE;     // assume it used to exist and is now gone
69    dvmUnlockThreadList();
70
71    RETURN_INT(result);
72}
73
74/*
75 * boolean holdsLock(Object object)
76 *
77 * Returns whether the current thread has a monitor lock on the specific
78 * object.
79 */
80static void Dalvik_java_lang_VMThread_holdsLock(const u4* args, JValue* pResult)
81{
82    Object* thisPtr = (Object*) args[0];
83    Object* object = (Object*) args[1];
84    Thread* thread;
85
86    if (object == NULL) {
87        dvmThrowException("Ljava/lang/NullPointerException;", NULL);
88        RETURN_VOID();
89    }
90
91    dvmLockThreadList(NULL);
92    thread = dvmGetThreadFromThreadObject(thisPtr);
93    int result = dvmHoldsLock(thread, object);
94    dvmUnlockThreadList();
95
96    RETURN_BOOLEAN(result);
97}
98
99/*
100 * void interrupt()
101 *
102 * Interrupt a thread that is waiting (or is about to wait) on a monitor.
103 */
104static void Dalvik_java_lang_VMThread_interrupt(const u4* args, JValue* pResult)
105{
106    Object* thisPtr = (Object*) args[0];
107    Thread* thread;
108
109    dvmLockThreadList(NULL);
110    thread = dvmGetThreadFromThreadObject(thisPtr);
111    if (thread != NULL)
112        dvmThreadInterrupt(thread);
113    dvmUnlockThreadList();
114    RETURN_VOID();
115}
116
117/*
118 * static boolean interrupted()
119 *
120 * Determine if the current thread has been interrupted.  Clears the flag.
121 */
122static void Dalvik_java_lang_VMThread_interrupted(const u4* args,
123    JValue* pResult)
124{
125    Thread* self = dvmThreadSelf();
126    bool interrupted;
127
128    UNUSED_PARAMETER(args);
129
130    interrupted = self->interrupted;
131    self->interrupted = false;
132    RETURN_BOOLEAN(interrupted);
133}
134
135/*
136 * boolean isInterrupted()
137 *
138 * Determine if the specified thread has been interrupted.  Does not clear
139 * the flag.
140 */
141static void Dalvik_java_lang_VMThread_isInterrupted(const u4* args,
142    JValue* pResult)
143{
144    Object* thisPtr = (Object*) args[0];
145    Thread* thread;
146    bool interrupted;
147
148    dvmLockThreadList(NULL);
149    thread = dvmGetThreadFromThreadObject(thisPtr);
150    if (thread != NULL)
151        interrupted = thread->interrupted;
152    else
153        interrupted = false;
154    dvmUnlockThreadList();
155
156    RETURN_BOOLEAN(interrupted);
157}
158
159/*
160 * void nameChanged(String newName)
161 *
162 * The name of the target thread has changed.  We may need to alert DDMS.
163 */
164static void Dalvik_java_lang_VMThread_nameChanged(const u4* args,
165    JValue* pResult)
166{
167    Object* thisPtr = (Object*) args[0];
168    StringObject* nameStr = (StringObject*) args[1];
169    Thread* thread;
170    int threadId = -1;
171
172    /* get the thread's ID */
173    dvmLockThreadList(NULL);
174    thread = dvmGetThreadFromThreadObject(thisPtr);
175    if (thread != NULL)
176        threadId = thread->threadId;
177    dvmUnlockThreadList();
178
179    dvmDdmSendThreadNameChange(threadId, nameStr);
180    //char* str = dvmCreateCstrFromString(nameStr);
181    //LOGI("UPDATE: threadid=%d now '%s'\n", threadId, str);
182    //free(str);
183
184    RETURN_VOID();
185}
186
187/*
188 * void setPriority(int newPriority)
189 *
190 * Alter the priority of the specified thread.  "newPriority" will range
191 * from Thread.MIN_PRIORITY to Thread.MAX_PRIORITY (1-10), with "normal"
192 * threads at Thread.NORM_PRIORITY (5).
193 */
194static void Dalvik_java_lang_VMThread_setPriority(const u4* args,
195    JValue* pResult)
196{
197    Object* thisPtr = (Object*) args[0];
198    int newPriority = args[1];
199    Thread* thread;
200
201    dvmLockThreadList(NULL);
202    thread = dvmGetThreadFromThreadObject(thisPtr);
203    if (thread != NULL)
204        dvmChangeThreadPriority(thread, newPriority);
205    //dvmDumpAllThreads(false);
206    dvmUnlockThreadList();
207
208    RETURN_VOID();
209}
210
211/*
212 * static void sleep(long msec, int nsec)
213 */
214static void Dalvik_java_lang_VMThread_sleep(const u4* args, JValue* pResult)
215{
216    Thread* self = dvmThreadSelf();
217    dvmThreadSleep(GET_ARG_LONG(args,0), args[2]);
218    RETURN_VOID();
219}
220
221/*
222 * public void yield()
223 *
224 * Causes the thread to temporarily pause and allow other threads to execute.
225 *
226 * The exact behavior is poorly defined.  Some discussion here:
227 *   http://www.cs.umd.edu/~pugh/java/memoryModel/archive/0944.html
228 */
229static void Dalvik_java_lang_VMThread_yield(const u4* args, JValue* pResult)
230{
231    UNUSED_PARAMETER(args);
232
233    sched_yield();
234
235    RETURN_VOID();
236}
237
238const DalvikNativeMethod dvm_java_lang_VMThread[] = {
239    { "create",         "(Ljava/lang/Thread;J)V",
240        Dalvik_java_lang_VMThread_create },
241    { "currentThread",  "()Ljava/lang/Thread;",
242        Dalvik_java_lang_VMThread_currentThread },
243    { "getStatus",      "()I",
244        Dalvik_java_lang_VMThread_getStatus },
245    { "holdsLock",      "(Ljava/lang/Object;)Z",
246        Dalvik_java_lang_VMThread_holdsLock },
247    { "interrupt",      "()V",
248        Dalvik_java_lang_VMThread_interrupt },
249    { "interrupted",    "()Z",
250        Dalvik_java_lang_VMThread_interrupted },
251    { "isInterrupted",  "()Z",
252        Dalvik_java_lang_VMThread_isInterrupted },
253    { "nameChanged",    "(Ljava/lang/String;)V",
254        Dalvik_java_lang_VMThread_nameChanged },
255    { "setPriority",    "(I)V",
256        Dalvik_java_lang_VMThread_setPriority },
257    { "sleep",          "(JI)V",
258        Dalvik_java_lang_VMThread_sleep },
259    { "yield",          "()V",
260        Dalvik_java_lang_VMThread_yield },
261    { NULL, NULL, NULL },
262};
263
264