]> git.saurik.com Git - cycript.git/blob - Handler.cpp
Commit a generally useful -gtiming implementation.
[cycript.git] / Handler.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2015 Jay Freeman (saurik)
3 */
4
5 /* GNU Affero General Public License, Version 3 {{{ */
6 /*
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #include <dlfcn.h>
23 #include <pthread.h>
24 #include <unistd.h>
25 #include <sstream>
26
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <sys/un.h>
32
33 #ifdef __APPLE__
34 #include <CoreFoundation/CoreFoundation.h>
35 #endif
36
37 #include "cycript.hpp"
38
39 #include "JavaScript.hpp"
40 #include "Parser.hpp"
41 #include "Pooling.hpp"
42
43 #include "Cycript.tab.hh"
44 #include "Driver.hpp"
45
46 struct CYExecute_ {
47 CYPool &pool_;
48 const char * volatile data_;
49 pthread_mutex_t mutex_;
50 pthread_cond_t condition_;
51 };
52
53 void CYPerform(void *arg) {
54 CYExecute_ *execute(reinterpret_cast<CYExecute_ *>(arg));
55
56 const char *data(execute->data_);
57 execute->data_ = NULL;
58 execute->data_ = CYExecute(CYGetJSContext(), execute->pool_, CYUTF8String(data));
59
60 pthread_mutex_lock(&execute->mutex_);
61 pthread_cond_signal(&execute->condition_);
62 pthread_mutex_unlock(&execute->mutex_);
63 }
64
65 struct CYClient :
66 CYData
67 {
68 int socket_;
69 pthread_t thread_;
70
71 CYClient(int socket) :
72 socket_(socket)
73 {
74 }
75
76 ~CYClient() {
77 _syscall(close(socket_));
78 }
79
80 void Handle() {
81 bool dispatch;
82 #ifdef __APPLE__
83 CFRunLoopRef loop(CFRunLoopGetMain());
84 if (CFStringRef mode = CFRunLoopCopyCurrentMode(loop)) {
85 dispatch = true;
86 CFRelease(mode);
87 } else
88 #endif
89 dispatch = false;
90
91 for (;;) {
92 uint32_t size;
93 if (!CYRecvAll(socket_, &size, sizeof(size)))
94 return;
95
96 CYLocalPool pool;
97 char *data(new(pool) char[size + 1]);
98 if (!CYRecvAll(socket_, data, size))
99 return;
100 data[size] = '\0';
101
102 std::string code(data, size);
103 CYExecute_ execute = {pool, code.c_str()};
104
105 pthread_mutex_init(&execute.mutex_, NULL);
106 pthread_cond_init(&execute.condition_, NULL);
107
108 if (!dispatch)
109 CYPerform(&execute);
110 #ifdef __APPLE__
111 else {
112 CFRunLoopSourceContext context;
113 memset(&context, 0, sizeof(context));
114 context.version = 0;
115 context.info = &execute;
116 context.perform = &CYPerform;
117
118 CFRunLoopSourceRef source(CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context));
119
120 pthread_mutex_lock(&execute.mutex_);
121
122 CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes);
123 CFRunLoopSourceSignal(source);
124
125 CFRunLoopWakeUp(loop);
126 pthread_cond_wait(&execute.condition_, &execute.mutex_);
127 pthread_mutex_unlock(&execute.mutex_);
128
129 CFRunLoopRemoveSource(loop, source, kCFRunLoopCommonModes);
130 CFRelease(source);
131 }
132 #endif
133
134 pthread_cond_destroy(&execute.condition_);
135 pthread_mutex_destroy(&execute.mutex_);
136
137 const char *json(execute.data_);
138 size = json == NULL ? _not(uint32_t) : strlen(json);
139
140 if (!CYSendAll(socket_, &size, sizeof(size)))
141 return;
142 if (json != NULL)
143 if (!CYSendAll(socket_, json, size))
144 return;
145 }
146 }
147 };
148
149 static void *OnClient(void *data) {
150 CYClient *client(reinterpret_cast<CYClient *>(data));
151 client->Handle();
152 delete client;
153 return NULL;
154 }
155
156 void CYHandleClient(int socket) {
157 // XXX: this leaks memory... really?
158 CYPool *pool(new CYPool());
159 CYClient *client(new(*pool) CYClient(socket));
160 _assert(pthread_create(&client->thread_, NULL, &OnClient, client) == 0);
161 }
162
163 static void CYHandleSocket(const char *path) {
164 int socket(_syscall(::socket(PF_UNIX, SOCK_STREAM, 0)));
165
166 struct sockaddr_un address;
167 memset(&address, 0, sizeof(address));
168 address.sun_family = AF_UNIX;
169 strcpy(address.sun_path, path);
170
171 _syscall(connect(socket, reinterpret_cast<sockaddr *>(&address), SUN_LEN(&address)));
172
173 CYInitializeDynamic();
174 CYHandleClient(socket);
175 }
176
177 _extern void CYHandleServer(pid_t pid) { try {
178 char path[1024];
179 sprintf(path, "/tmp/.s.cy.%u", pid);
180 CYHandleSocket(path);
181 } catch (const CYException &error) {
182 CYPool pool;
183 fprintf(stderr, "%s\n", error.PoolCString(pool));
184 } }
185
186 _extern char *MSmain0(int argc, char *argv[]) { try {
187 _assert(argc == 2);
188 CYHandleSocket(argv[1]);
189
190 static void *handle(NULL);
191 if (handle == NULL) {
192 Dl_info info;
193 _assert(dladdr(reinterpret_cast<void *>(&MSmain0), &info) != 0);
194 handle = dlopen(info.dli_fname, RTLD_NOLOAD);
195 }
196
197 return NULL;
198 } catch (const CYException &error) {
199 CYPool pool;
200 return strdup(error.PoolCString(pool));
201 } }
202
203 struct CYServer {
204 pthread_t thread_;
205 uint16_t port_;
206 int socket_;
207
208 CYServer(uint16_t port) :
209 port_(port),
210 socket_(-1)
211 {
212 }
213
214 ~CYServer() {
215 if (socket_ != -1)
216 _syscall(close(socket_));
217 }
218
219 void Listen() {
220 socket_ = _syscall(::socket(PF_INET, SOCK_STREAM, 0)); try {
221 int value;
222 _syscall(::setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &(value = 1), sizeof(value)));
223
224 sockaddr_in address;
225 address.sin_family = AF_INET;
226 address.sin_addr.s_addr = INADDR_ANY;
227 address.sin_port = htons(port_);
228 _syscall(::bind(socket_, reinterpret_cast<sockaddr *>(&address), sizeof(address)));
229
230 _syscall(::listen(socket_, -1));
231
232 for (;;) {
233 socklen_t length(sizeof(address));
234 int socket(_syscall(::accept(socket_, reinterpret_cast<sockaddr *>(&address), &length)));
235 CYHandleClient(socket);
236 }
237 } catch (const CYException &error) {
238 CYPool pool;
239 fprintf(stderr, "%s\n", error.PoolCString(pool));
240 }
241 }
242 };
243
244 static void *OnServer(void *data) {
245 CYServer *server(reinterpret_cast<CYServer *>(data));
246 server->Listen();
247 delete server;
248 return NULL;
249 }
250
251 _extern void CYListenServer(short port) {
252 CYInitializeDynamic();
253
254 CYServer *server(new CYServer(port));
255 _assert(pthread_create(&server->thread_, NULL, &OnServer, server) == 0);
256 }