1563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/*
2563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
3563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark *           (C) 2007 Graham Dennis (graham.dennis@gmail.com)
4563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark *           (C) 2007 Eric Seidel <eric@webkit.org>
5563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark *
6563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Redistribution and use in source and binary forms, with or without
7563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * modification, are permitted provided that the following conditions
8563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * are met:
9563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark *
10563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * 1.  Redistributions of source code must retain the above copyright
11563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark *     notice, this list of conditions and the following disclaimer.
12563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * 2.  Redistributions in binary form must reproduce the above copyright
13563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark *     notice, this list of conditions and the following disclaimer in the
14563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark *     documentation and/or other materials provided with the distribution.
15563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark *     its contributors may be used to endorse or promote products derived
17563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark *     from this software without specific prior written permission.
18563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark *
19563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
30563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
31643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#include "config.h"
32563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include "JavaScriptThreading.h"
33563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
34563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include <CoreFoundation/CoreFoundation.h>
35563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include <JavaScriptCore/JavaScriptCore.h>
36563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include <pthread.h>
37563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include <wtf/Assertions.h>
38563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include <wtf/HashSet.h>
39563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
402fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic JSContextGroupRef javaScriptThreadsGroup;
412fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
42563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic pthread_mutex_t javaScriptThreadsMutex = PTHREAD_MUTEX_INITIALIZER;
43563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic bool javaScriptThreadsShouldTerminate;
44563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
45563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic const int javaScriptThreadsCount = 4;
46563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
47563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarktypedef HashSet<pthread_t> ThreadSet;
48563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
49563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic ThreadSet* javaScriptThreads()
50563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{
51563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    ASSERT(pthread_mutex_trylock(&javaScriptThreadsMutex) == EBUSY);
52563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    static ThreadSet staticJavaScriptThreads;
53563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    return &staticJavaScriptThreads;
54563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
55563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
562fc2651226baac27029e38c9d6ef883fa32084dbSteve Block// This function exercises JSC in a loop until javaScriptThreadsShouldTerminate
572fc2651226baac27029e38c9d6ef883fa32084dbSteve Block// becomes true or it probabilistically decides to spawn a replacement thread and exit.
58563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvoid* runJavaScriptThread(void* arg)
59563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{
602fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    static const char* const script =
61563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        "var array = [];"
622fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        "for (var i = 0; i < 1024; i++) {"
63563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        "    array.push(String(i));"
64563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        "}";
65563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
662fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    pthread_mutex_lock(&javaScriptThreadsMutex);
672fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    JSGlobalContextRef ctx = JSGlobalContextCreateInGroup(javaScriptThreadsGroup, 0);
682fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    pthread_mutex_unlock(&javaScriptThreadsMutex);
692fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
702fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    pthread_mutex_lock(&javaScriptThreadsMutex);
712fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    JSStringRef scriptRef = JSStringCreateWithUTF8CString(script);
722fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    pthread_mutex_unlock(&javaScriptThreadsMutex);
73563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    while (1) {
752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        pthread_mutex_lock(&javaScriptThreadsMutex);
76563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        JSValueRef exception = 0;
77563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception);
78563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        ASSERT(!exception);
792fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        pthread_mutex_unlock(&javaScriptThreadsMutex);
80563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
81563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        pthread_mutex_lock(&javaScriptThreadsMutex);
822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        size_t valuesCount = 1024;
832fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        JSValueRef values[valuesCount];
842fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        for (size_t i = 0; i < valuesCount; ++i)
852fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            values[i] = JSObjectMake(ctx, 0, 0);
862fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        pthread_mutex_unlock(&javaScriptThreadsMutex);
87563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
88563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        // Check for cancellation.
892fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if (javaScriptThreadsShouldTerminate)
902fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            goto done;
91563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
92563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        // Respawn probabilistically.
93563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        if (random() % 5 == 0) {
942fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            pthread_mutex_lock(&javaScriptThreadsMutex);
95563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark            pthread_t pthread;
96563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark            pthread_create(&pthread, 0, &runJavaScriptThread, 0);
97563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark            pthread_detach(pthread);
98563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark            javaScriptThreads()->add(pthread);
99563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark            pthread_mutex_unlock(&javaScriptThreadsMutex);
1002fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            goto done;
101563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        }
102563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    }
1032fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1042fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockdone:
1052fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    pthread_mutex_lock(&javaScriptThreadsMutex);
1062fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    JSStringRelease(scriptRef);
1072fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    JSGarbageCollect(ctx);
1082fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    JSGlobalContextRelease(ctx);
1092fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    javaScriptThreads()->remove(pthread_self());
1102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    pthread_mutex_unlock(&javaScriptThreadsMutex);
1112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    return 0;
112563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
113563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
114563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvoid startJavaScriptThreads()
115563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{
1162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    javaScriptThreadsGroup = JSContextGroupCreate();
1172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
118563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    pthread_mutex_lock(&javaScriptThreadsMutex);
119563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
120563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    for (int i = 0; i < javaScriptThreadsCount; i++) {
121563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        pthread_t pthread;
122563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        pthread_create(&pthread, 0, &runJavaScriptThread, 0);
123563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        pthread_detach(pthread);
124563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        javaScriptThreads()->add(pthread);
125563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    }
126563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
127563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    pthread_mutex_unlock(&javaScriptThreadsMutex);
128563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
129563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
130563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvoid stopJavaScriptThreads()
131563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{
132563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    pthread_mutex_lock(&javaScriptThreadsMutex);
133563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
134563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    javaScriptThreadsShouldTerminate = true;
135563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
136563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    pthread_mutex_unlock(&javaScriptThreadsMutex);
137563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
138563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    while (true) {
139563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        pthread_mutex_lock(&javaScriptThreadsMutex);
140563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        int threadCount = javaScriptThreads()->size();
141563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        pthread_mutex_unlock(&javaScriptThreadsMutex);
142563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
143563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        if (!threadCount)
144563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark            break;
145563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
146563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        usleep(1000);
147563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    }
148563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
149