Coverage Report

Created: 2025-10-29 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/tools/xst.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-2025  Moddable Tech, Inc.
3
 *
4
 *   This file is part of the Moddable SDK Tools.
5
 * 
6
 *   The Moddable SDK Tools is free software: you can redistribute it and/or modify
7
 *   it under the terms of the GNU General Public License as published by
8
 *   the Free Software Foundation, either version 3 of the License, or
9
 *   (at your option) any later version.
10
 * 
11
 *   The Moddable SDK Tools is distributed in the hope that it will be useful,
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *   GNU General Public License for more details.
15
 * 
16
 *   You should have received a copy of the GNU General Public License
17
 *   along with the Moddable SDK Tools.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 */
20
21
#include "xsAll.h"
22
#include "xsScript.h"
23
#include "xs.h"
24
25
extern int fuzz(int argc, char* argv[]);
26
extern void fx_print(xsMachine* the);
27
extern void fxBuildAgent(xsMachine* the);
28
extern void fxBuildFuzz(xsMachine* the);
29
extern txScript* fxLoadScript(txMachine* the, txString path, txUnsigned flags);
30
extern void fxFulfillModuleFile(txMachine* the);
31
extern void fxRejectModuleFile(txMachine* the);
32
extern void fxRunLoop(txMachine* the);
33
extern void fxRunModuleFile(txMachine* the, txString path);
34
extern void fxRunProgramFile(txMachine* the, txString path, txUnsigned flags);
35
extern int main262(int argc, char* argv[]);
36
37
struct sxJob {
38
  txMachine* the;
39
  txSlot self;
40
  txSlot function;
41
  txSlot argument;
42
};
43
44
struct sxSharedTimer {
45
  txSharedTimer* next;
46
  txThread thread;
47
  txNumber when;
48
  txNumber interval;
49
  txSharedTimerCallback callback;
50
  txInteger refconSize;
51
  char refcon[1];
52
};
53
54
static void fxPrintUsage();
55
56
static void fx_agent_broadcast(xsMachine* the);
57
static void fx_agent_getReport(xsMachine* the);
58
static void fx_agent_leaving(xsMachine* the);
59
static void fx_agent_monotonicNow(xsMachine* the);
60
static void fx_agent_receiveBroadcast(xsMachine* the);
61
static void fx_agent_report(xsMachine* the);
62
static void fx_agent_sleep(xsMachine* the);
63
static void fx_agent_start(xsMachine* the);
64
#if mxWindows
65
static unsigned int __stdcall fx_agent_start_aux(void* it);
66
#else
67
static void* fx_agent_start_aux(void* it);
68
#endif
69
static void fx_createRealm(xsMachine* the);
70
static void fx_detachArrayBuffer(xsMachine* the);
71
static void fx_evalScript(xsMachine* the);
72
static void fx_gc(xsMachine* the);
73
static void fx_isLockedDown(xsMachine* the);
74
static void fx_metering(xsMachine* the);
75
static void fx_runScript(xsMachine* the);
76
77
extern void fx_clearTimer(txMachine* the);
78
static void fx_destroyTimer(void* data);
79
static void fx_markTimer(txMachine* the, void* it, txMarkRoot markRoot);
80
static void fx_setInterval(txMachine* the);
81
static void fx_setTimeout(txMachine* the);
82
static void fx_setTimer(txMachine* the, txNumber interval, txBoolean repeat);
83
84
txAgentCluster gxAgentCluster;
85
86
#if OSSFUZZ
87
int omain(int argc, char* argv[]) 
88
#else
89
int main(int argc, char* argv[]) 
90
#endif
91
0
{
92
0
  txAgentCluster* agentCluster = &gxAgentCluster;
93
0
  int argi;
94
0
  int option = 0;
95
0
  int profiling = 0;
96
0
  char path[C_PATH_MAX];
97
0
  char* dot;
98
#if mxWindows
99
    char* harnessPath = "..\\harness";
100
#else
101
0
    char* harnessPath = "../harness";
102
0
#endif
103
0
  int error = 0;
104
  
105
0
  c_memset(agentCluster, 0, sizeof(txAgentCluster));
106
0
  fxCreateMutex(&(agentCluster->mainMutex));
107
0
  fxCreateCondition(&(agentCluster->countCondition));
108
0
  fxCreateMutex(&(agentCluster->countMutex));
109
0
  fxCreateCondition(&(agentCluster->dataCondition));
110
0
  fxCreateMutex(&(agentCluster->dataMutex));
111
0
  fxCreateMutex(&(agentCluster->reportMutex));
112
113
0
  if (argc == 1) {
114
0
    fxPrintUsage();
115
0
    return 1;
116
0
  }
117
0
  for (argi = 1; argi < argc; argi++) {
118
0
    if (argv[argi][0] != '-')
119
0
      continue;
120
  
121
0
    if (!strcmp(argv[argi], "-c"))
122
0
      option = 4;
123
0
    else if (!strcmp(argv[argi], "-i")) {
124
0
      argi++;
125
0
      option = 4;
126
0
    }
127
0
    else if (!strcmp(argv[argi], "-l"))
128
0
      option = 4;
129
0
    else if (!strcmp(argv[argi], "-lc"))
130
0
      option = 4;
131
0
    else if (!strcmp(argv[argi], "-o")) {
132
0
      argi++;
133
0
      option = 4;
134
0
    }
135
0
    else if (!strcmp(argv[argi], "-t"))
136
0
      option = 4;
137
138
0
    else if (!strcmp(argv[argi], "-h"))
139
0
      fxPrintUsage();
140
0
    else if (!strcmp(argv[argi], "-b"))
141
0
      option = 7;
142
0
    else if (!strcmp(argv[argi], "-e"))
143
0
      option = 1;
144
0
    else if (!strcmp(argv[argi], "-f"))
145
0
      option = 5;
146
0
    else if (!strcmp(argv[argi], "-j"))
147
0
      option = 6;
148
0
    else if (!strcmp(argv[argi], "-m"))
149
0
      option = 2;
150
0
    else if (!strcmp(argv[argi], "-p"))
151
0
      profiling = 1;
152
0
    else if (!strcmp(argv[argi], "-s"))
153
0
      option = 3;
154
0
    else if (!strcmp(argv[argi], "-v"))
155
0
      printf("XS %d.%d.%d, slot %zu bytes, ID %zu bytes\n", XS_MAJOR_VERSION, XS_MINOR_VERSION, XS_PATCH_VERSION, sizeof(txSlot), sizeof(txID));
156
0
    else {
157
0
      fxPrintUsage();
158
0
      return 1;
159
0
    }
160
0
  }
161
0
  if (option == 0) {
162
0
    if (c_realpath(harnessPath, path))
163
0
      option  = 4;
164
0
  }
165
0
  if (option == 4) {
166
0
    error = main262(argc, argv);
167
0
  }
168
0
  else if (option == 5) {
169
0
    error = fuzz(argc, argv);
170
0
  }
171
0
  else {
172
0
    xsCreation _creation = {
173
0
      16 * 1024 * 1024,   /* initialChunkSize */
174
0
      16 * 1024 * 1024,   /* incrementalChunkSize */
175
0
      1 * 1024 * 1024,  /* initialHeapCount */
176
0
      1 * 1024 * 1024,  /* incrementalHeapCount */
177
0
      256 * 1024,     /* stackCount */
178
0
      1024,         /* initialKeyCount */
179
0
      1024,       /* incrementalKeyCount */
180
0
      1993,         /* nameModulo */
181
0
      127,        /* symbolModulo */
182
0
      64 * 1024,      /* parserBufferSize */
183
0
      1993,       /* parserTableModulo */
184
0
    };
185
0
    xsCreation* creation = &_creation;
186
0
    xsMachine* machine;
187
0
        machine = xsCreateMachine(creation, "xst", NULL);
188
0
    xsBeginMetering(machine, NULL, 0);
189
0
    {
190
0
    if (profiling)
191
0
      fxStartProfiling(machine);
192
193
0
    xsBeginHost(machine);
194
0
    {
195
0
      xsVars(2);
196
0
      xsTry {
197
0
        fxBuildAgent(machine);
198
0
        fxBuildFuzz(machine);
199
200
0
        xsVar(0) = xsUndefined;
201
0
        the->rejection = &xsVar(0);
202
0
        for (argi = 1; argi < argc; argi++) {
203
0
          if (argv[argi][0] == '-')
204
0
            continue;
205
0
          if (option == 1) {
206
0
            xsVar(1) = xsGet(xsGlobal, xsID("$262"));
207
0
            xsResult = xsString(argv[argi]);
208
0
            xsCall1(xsVar(1), xsID("evalScript"), xsResult);
209
0
          }
210
0
          else {
211
0
            if (!c_realpath(argv[argi], path))
212
0
              xsURIError("file not found: %s", argv[argi]);
213
0
            dot = strrchr(path, '.');
214
0
            if ((option == 6) || (option == 7)) {
215
0
              FILE* file = C_NULL;
216
0
              char *buffer = C_NULL;
217
0
              xsTry {
218
0
                file = fopen(path, "r");
219
0
                if (!file)
220
0
                  xsUnknownError("can't open file");
221
0
                fseek(file, 0, SEEK_END);
222
0
                size_t size = ftell(file);
223
0
                fseek(file, 0, SEEK_SET);
224
0
                buffer = c_malloc(size + 1);
225
0
                if (!buffer)
226
0
                  xsUnknownError("not enough memory");
227
0
                if (size != fread(buffer, 1, size, file)) 
228
0
                  xsUnknownError("can't read file");
229
0
                buffer[size] = 0;
230
0
                fclose(file);
231
0
                file = C_NULL;
232
0
                xsResult = xsArrayBuffer(buffer, (txInteger)size);
233
0
                c_free(buffer);
234
0
                buffer = C_NULL;
235
0
                xsVar(1) = xsNew0(xsGlobal, xsID("TextDecoder"));
236
0
                xsResult = xsCall1(xsVar(1), xsID("decode"), xsResult);
237
0
                if (option == 6) {
238
0
                  xsVar(1) = xsGet(xsGlobal, xsID("JSON"));
239
0
                  xsResult = xsCall1(xsVar(1), xsID("parse"), xsResult);
240
0
                }
241
0
                else {
242
0
                  xsResult = xsCall1(xsGlobal, xsID("eval"), xsResult);
243
0
                }
244
0
              }
245
0
              xsCatch {
246
0
                if (buffer)
247
0
                  c_free(buffer);
248
0
                if (file)
249
0
                  fclose(file);
250
0
              }
251
0
            }
252
0
            else
253
0
            if (((option == 0) && dot && !c_strcmp(dot, ".mjs")) || (option == 2))
254
0
              fxRunModuleFile(the, path);
255
0
            else
256
0
              fxRunProgramFile(the, path, mxProgramFlag | mxDebugFlag);
257
0
          }
258
0
        }
259
0
        fxRunLoop(the);
260
0
        if (xsTest(xsVar(0))) 
261
0
          xsThrow(xsVar(0));
262
0
      }
263
0
      xsCatch {
264
0
        fprintf(stderr, "%s\n", xsToString(xsException));
265
0
        error = 1;
266
0
      }
267
0
    }
268
0
    fxCheckUnhandledRejections(machine, 1);
269
0
    xsEndHost(machine);
270
0
    if (profiling)
271
0
      fxStopProfiling(machine, C_NULL);
272
0
    }
273
0
    xsEndMetering(machine);
274
0
    if (machine->exitStatus) {
275
0
      fprintf(stderr, "Error: %s\n", fxAbortString(machine->exitStatus));
276
0
      error = 1;
277
0
    }
278
0
    xsDeleteMachine(machine);
279
0
  }
280
0
  return error;
281
0
}
282
283
extern void modInstallTextDecoder(xsMachine *the);
284
extern void modInstallTextEncoder(xsMachine *the);
285
extern void modInstallBase64(xsMachine *the);
286
287
void fxBuildAgent(xsMachine* the) 
288
0
{
289
0
  txSlot* slot;
290
0
  txSlot* agent;
291
0
  txSlot* global;
292
293
0
  slot = fxLastProperty(the, fxNewHostObject(the, NULL));
294
0
  slot = fxNextHostFunctionProperty(the, slot, fx_agent_broadcast, 2, xsID("broadcast"), XS_DONT_ENUM_FLAG); 
295
0
  slot = fxNextHostFunctionProperty(the, slot, fx_agent_getReport, 0, xsID("getReport"), XS_DONT_ENUM_FLAG); 
296
0
  slot = fxNextHostFunctionProperty(the, slot, fx_agent_monotonicNow, 0, xsID("monotonicNow"), XS_DONT_ENUM_FLAG); 
297
0
  slot = fxNextHostFunctionProperty(the, slot, fx_agent_sleep, 1, xsID("sleep"), XS_DONT_ENUM_FLAG); 
298
0
  slot = fxNextHostFunctionProperty(the, slot, fx_agent_start, 1, xsID("start"), XS_DONT_ENUM_FLAG); 
299
0
  agent = the->stack;
300
301
0
  mxPush(mxGlobal);
302
0
  global = the->stack;
303
304
0
  mxPush(mxObjectPrototype);
305
0
  slot = fxLastProperty(the, fxNewObjectInstance(the));
306
0
  slot = fxNextSlotProperty(the, slot, agent, xsID("agent"), XS_GET_ONLY);
307
0
  slot = fxNextHostFunctionProperty(the, slot, fx_createRealm, 0, xsID("createRealm"), XS_DONT_ENUM_FLAG); 
308
0
  slot = fxNextHostFunctionProperty(the, slot, fx_detachArrayBuffer, 1, xsID("detachArrayBuffer"), XS_DONT_ENUM_FLAG); 
309
0
  slot = fxNextHostFunctionProperty(the, slot, fx_gc, 1, xsID("gc"), XS_DONT_ENUM_FLAG); 
310
0
  slot = fxNextHostFunctionProperty(the, slot, fx_evalScript, 1, xsID("evalScript"), XS_DONT_ENUM_FLAG); 
311
0
  slot = fxNextHostFunctionProperty(the, slot, fx_isLockedDown, 1, xsID("isLockedDown"), XS_DONT_ENUM_FLAG); 
312
0
  slot = fxNextHostFunctionProperty(the, slot, fx_metering, 1, xsID("metering"), XS_DONT_ENUM_FLAG); 
313
0
  slot = fxNextSlotProperty(the, slot, global, xsID("global"), XS_GET_ONLY);
314
315
0
  slot = fxLastProperty(the, fxToInstance(the, global));
316
0
  slot = fxNextSlotProperty(the, slot, the->stack, xsID("$262"), XS_DONT_ENUM_FLAG);
317
0
  slot = fxNextHostFunctionProperty(the, slot, fx_print, 1, xsID("print"), XS_DONT_ENUM_FLAG);
318
0
  slot = fxNextHostFunctionProperty(the, slot, fx_runScript, 1, xsID("runScript"), XS_DONT_ENUM_FLAG);
319
0
  slot = fxNextHostFunctionProperty(the, slot, fx_clearTimer, 1, xsID("clearInterval"), XS_DONT_ENUM_FLAG);
320
0
  slot = fxNextHostFunctionProperty(the, slot, fx_clearTimer, 1, xsID("clearTimeout"), XS_DONT_ENUM_FLAG);
321
0
  slot = fxNextHostFunctionProperty(the, slot, fx_setInterval, 1, xsID("setInterval"), XS_DONT_ENUM_FLAG);
322
0
  slot = fxNextHostFunctionProperty(the, slot, fx_setTimeout, 1, xsID("setTimeout"), XS_DONT_ENUM_FLAG);
323
  
324
0
  slot = fxNextHostFunctionProperty(the, slot, fx_harden, 1, xsID("harden"), XS_DONT_ENUM_FLAG);
325
0
  slot = fxNextHostFunctionProperty(the, slot, fx_lockdown, 0, xsID("lockdown"), XS_DONT_ENUM_FLAG);
326
  
327
0
  slot = fxNextHostFunctionProperty(the, slot, fx_unicodeCompare, 2, xsID("unicodeCompare"), XS_DONT_ENUM_FLAG);
328
329
0
  mxPop();
330
0
  mxPop();
331
  
332
0
  modInstallTextDecoder(the);
333
0
  modInstallTextEncoder(the);
334
0
  modInstallBase64(the);
335
0
}
336
337
void fxPrintUsage()
338
0
{
339
0
  printf("xst [-h] [-e] [-f] [-j] [-m] [-p] [-s] [-t] [-v] strings...\n");
340
0
  printf("\t-b: strings are paths to script buffers\n");
341
0
  printf("\t-e: eval strings\n");
342
0
  printf("\t-f: fuzz with REPRL harness\n");
343
0
  printf("\t-h: print this help message\n");
344
0
  printf("\t-j: strings are paths to JSON buffers\n");
345
0
  printf("\t-m: strings are paths to modules\n");
346
0
  printf("\t-p: profile\n");
347
0
  printf("\t-s: strings are paths to scripts\n");
348
0
  printf("\t-t: strings are paths to test262 cases or directories\n");
349
0
  printf("\t-v: print XS version\n");
350
0
  printf("without -b, -e, -f, -j, -m, -s, or -t:\n");
351
0
  printf("\tif ../harness exists, strings are paths to test262 cases or directories\n");
352
0
  printf("\telse if the extension is .mjs, strings are paths to modules\n");
353
0
  printf("\telse strings are paths to scripts\n");
354
0
}
355
356
void fx_evalScript(xsMachine* the)
357
0
{
358
0
  txSlot* realm;
359
0
  txSlot* module = mxFunctionInstanceHome(mxFunction->value.reference)->value.home.module;
360
0
  if (!module) module = mxProgram.value.reference;
361
0
  realm = mxModuleInstanceInternal(module)->value.module.realm;
362
0
  txStringStream aStream;
363
0
  aStream.slot = mxArgv(0);
364
0
  aStream.offset = 0;
365
0
  aStream.size = mxStringLength(fxToString(the, mxArgv(0)));
366
0
  fxRunScript(the, fxParseScript(the, &aStream, fxStringGetter, mxProgramFlag | mxDebugFlag), mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, module);
367
0
  mxPullSlot(mxResult);
368
0
}
369
370
void fx_gc(xsMachine* the)
371
0
{
372
0
  xsCollectGarbage();
373
0
}
374
375
void fx_isLockedDown(xsMachine* the)
376
0
{
377
0
  xsResult = (mxProgram.value.reference->flag & XS_DONT_MARSHALL_FLAG) ? xsTrue : xsFalse;
378
0
}
379
380
void fx_metering(xsMachine* the)
381
0
{
382
0
#ifdef mxMetering
383
0
  xsResult = xsNumber(the->meterIndex);
384
0
#endif  
385
0
}
386
387
void fx_print(xsMachine* the)
388
131k
{
389
131k
  xsIntegerValue c = xsToInteger(xsArgc), i;
390
131k
  xsStringValue string, p, q;
391
131k
  xsVars(1);
392
131k
  xsVar(0) = xsGet(xsGlobal, xsID("String"));
393
380k
  for (i = 0; i < c; i++) {
394
248k
    if (i)
395
117k
      fprintf(stdout, " ");
396
248k
    xsArg(i) = xsCallFunction1(xsVar(0), xsUndefined, xsArg(i));
397
248k
    p = string = xsToString(xsArg(i));
398
248k
  #if mxCESU8
399
6.33M
    for (;;) {
400
6.33M
      xsIntegerValue character;
401
6.33M
      q = fxUTF8Decode(p, &character);
402
6.36M
    again:
403
6.36M
      if (character == C_EOF)
404
248k
        break;
405
6.11M
      if (character == 0) {
406
1.26M
        if (p > string) {
407
209k
          char c = *p;
408
209k
          *p = 0;
409
209k
          fprintf(stdout, "%s", string);
410
209k
          *p = c;
411
209k
        }
412
1.26M
        string = q;
413
1.26M
      }
414
4.85M
      else if ((0x0000D800 <= character) && (character <= 0x0000DBFF)) {
415
45.6k
        xsStringValue r = q;
416
45.6k
        xsIntegerValue surrogate;
417
45.6k
        q = fxUTF8Decode(r, &surrogate);
418
45.6k
        if ((0x0000DC00 <= surrogate) && (surrogate <= 0x0000DFFF)) {
419
13.3k
          char buffer[5];
420
13.3k
          character = (txInteger)(0x00010000 + ((character & 0x03FF) << 10) + (surrogate & 0x03FF));
421
13.3k
          if (p > string) {
422
6.17k
            char c = *p;
423
6.17k
            *p = 0;
424
6.17k
            fprintf(stdout, "%s", string);
425
6.17k
            *p = c;
426
6.17k
          }
427
13.3k
          p = fxUTF8Encode(buffer, character);
428
13.3k
          *p = 0;
429
13.3k
          fprintf(stdout, "%s", buffer);
430
13.3k
          string = q;
431
13.3k
        }
432
32.3k
        else {
433
32.3k
          p = r;
434
32.3k
          character = surrogate;
435
32.3k
          goto again;
436
32.3k
        }
437
45.6k
      }
438
6.08M
      p = q;
439
6.08M
    }
440
248k
  #endif  
441
248k
    fprintf(stdout, "%s", string);
442
248k
  }
443
131k
  fprintf(stdout, "\n");
444
131k
}
445
446
void fx_runScript(xsMachine* the)
447
0
{
448
0
  txSlot* realm = mxProgram.value.reference->next->value.module.realm;
449
0
  char path[C_PATH_MAX];
450
0
  txUnsigned flags = mxProgramFlag | mxDebugFlag;
451
0
  if (!c_realpath(fxToString(the, mxArgv(0)), path))
452
0
    xsURIError("file not found");
453
0
  txScript* script = fxLoadScript(the, path, flags);
454
0
  mxModuleInstanceInternal(mxProgram.value.reference)->value.module.id = fxID(the, path);
455
0
  fxRunScript(the, script, mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, mxProgram.value.reference);
456
0
  mxPullSlot(mxResult);
457
0
}
458
459
/* $262 */
460
461
void fx_agent_broadcast(xsMachine* the)
462
0
{
463
0
  txAgentCluster* agentCluster = &gxAgentCluster;
464
0
  if (xsIsInstanceOf(xsArg(0), xsTypedArrayPrototype)) {
465
0
    xsArg(0) = xsGet(xsArg(0), xsID("buffer"));
466
0
  }
467
0
    fxLockMutex(&(agentCluster->dataMutex));
468
0
  agentCluster->dataBuffer = xsMarshallAlien(xsArg(0));
469
0
  if (mxArgc > 1)
470
0
    agentCluster->dataValue = xsToInteger(xsArg(1));
471
0
  fxWakeAllCondition(&(agentCluster->dataCondition));
472
0
    fxUnlockMutex(&(agentCluster->dataMutex));
473
    
474
0
    fxLockMutex(&(agentCluster->countMutex));
475
0
    while (agentCluster->count > 0)
476
0
    fxSleepCondition(&(agentCluster->countCondition), &(agentCluster->countMutex));
477
0
    fxUnlockMutex(&(agentCluster->countMutex));
478
0
}
479
480
void fx_agent_getReport(xsMachine* the)
481
0
{
482
0
  txAgentCluster* agentCluster = &gxAgentCluster;
483
0
  txAgentReport* report = C_NULL;
484
0
    fxLockMutex(&(agentCluster->reportMutex));
485
0
  report = agentCluster->firstReport;
486
0
  if (report)
487
0
    agentCluster->firstReport = report->next;
488
0
    fxUnlockMutex(&(agentCluster->reportMutex));
489
0
    if (report) {
490
0
      xsResult = xsString(report->message);
491
0
      c_free(report);
492
0
    }
493
0
    else
494
0
      xsResult = xsNull;
495
0
}
496
497
void fx_agent_leaving(xsMachine* the)
498
0
{
499
0
}
500
501
void fx_agent_monotonicNow(xsMachine* the)
502
0
{
503
0
  xsResult = xsNumber(mxMonotonicNow());
504
0
}
505
506
void fx_agent_receiveBroadcast(xsMachine* the)
507
0
{
508
0
  txAgentCluster* agentCluster = &gxAgentCluster;
509
0
   fxLockMutex(&(agentCluster->dataMutex));
510
0
  while (agentCluster->dataBuffer == NULL)
511
0
    fxSleepCondition(&(agentCluster->dataCondition), &(agentCluster->dataMutex));
512
0
  xsResult = xsDemarshallAlien(agentCluster->dataBuffer);
513
0
    fxUnlockMutex(&(agentCluster->dataMutex));
514
  
515
0
    fxLockMutex(&(agentCluster->countMutex));
516
0
    agentCluster->count--;
517
0
    fxWakeCondition(&(agentCluster->countCondition));
518
0
    fxUnlockMutex(&(agentCluster->countMutex));
519
    
520
0
  xsCallFunction2(xsArg(0), xsGlobal, xsResult, xsInteger(agentCluster->dataValue));
521
0
}
522
523
void fx_agent_report(xsMachine* the)
524
0
{
525
0
  txAgentCluster* agentCluster = &gxAgentCluster;
526
0
  xsStringValue message = xsToString(xsArg(0));
527
0
  xsIntegerValue messageLength = mxStringLength(message);
528
0
  txAgentReport* report = c_malloc(sizeof(txAgentReport) + messageLength);
529
0
  if (!report) xsUnknownError("not enough memory");
530
0
    report->next = C_NULL;
531
0
  c_memcpy(&(report->message[0]), message, messageLength + 1);
532
0
    fxLockMutex(&(agentCluster->reportMutex));
533
0
    if (agentCluster->firstReport)
534
0
    agentCluster->lastReport->next = report;
535
0
    else
536
0
    agentCluster->firstReport = report;
537
0
  agentCluster->lastReport = report;
538
0
    fxUnlockMutex(&(agentCluster->reportMutex));
539
0
}
540
541
void fx_agent_sleep(xsMachine* the)
542
0
{
543
0
  xsIntegerValue delay = xsToInteger(xsArg(0));
544
#if mxWindows
545
  Sleep(delay);
546
#else 
547
0
  usleep(delay * 1000);
548
0
#endif
549
0
}
550
551
void fx_agent_start(xsMachine* the)
552
0
{
553
0
  xsStringValue script = xsToString(xsArg(0));
554
0
  xsIntegerValue scriptLength = mxStringLength(script);
555
0
  txAgentCluster* agentCluster = &gxAgentCluster;
556
0
  txAgent* agent = c_malloc(sizeof(txAgent) + scriptLength);
557
0
  if (!agent) xsUnknownError("not enough memory");
558
0
  c_memset(agent, 0, sizeof(txAgent));
559
0
  if (agentCluster->firstAgent)
560
0
    agentCluster->lastAgent->next = agent;
561
0
  else
562
0
    agentCluster->firstAgent = agent;
563
0
  agentCluster->lastAgent = agent;
564
0
  agentCluster->count++;
565
0
  agent->scriptLength = scriptLength;
566
0
  c_memcpy(&(agent->script[0]), script, scriptLength + 1);
567
#if mxWindows
568
  agent->thread = (HANDLE)_beginthreadex(NULL, 0, fx_agent_start_aux, agent, 0, NULL);
569
#elif mxMacOSX
570
  pthread_attr_t attr; 
571
  pthread_t self = pthread_self();
572
  size_t size = pthread_get_stacksize_np(self);
573
  pthread_attr_init(&attr);
574
  pthread_attr_setstacksize(&attr, size);
575
    pthread_create(&(agent->thread), &attr, &fx_agent_start_aux, agent);
576
#else 
577
0
    pthread_create(&(agent->thread), NULL, &fx_agent_start_aux, agent);
578
0
#endif
579
0
}
580
581
#if mxWindows
582
unsigned int __stdcall fx_agent_start_aux(void* it)
583
#else
584
void* fx_agent_start_aux(void* it)
585
#endif
586
0
{
587
0
  xsCreation creation = {
588
0
    16 * 1024 * 1024,   /* initialChunkSize */
589
0
    16 * 1024 * 1024,   /* incrementalChunkSize */
590
0
    1 * 1024 * 1024,  /* initialHeapCount */
591
0
    1 * 1024 * 1024,  /* incrementalHeapCount */
592
0
    4096,         /* stackCount */
593
0
    1024,         /* initialKeyCount */
594
0
    1024,       /* incrementalKeyCount */
595
0
    1993,         /* nameModulo */
596
0
    127,        /* symbolModulo */
597
0
    64 * 1024,      /* parserBufferSize */
598
0
    1993,       /* parserTableModulo */
599
0
  };
600
0
  txAgent* agent = it;
601
0
  xsMachine* machine = xsCreateMachine(&creation, "xst-agent", NULL);
602
0
  xsBeginHost(machine);
603
0
  {
604
0
    xsTry {
605
0
      txSlot* slot;
606
0
      txSlot* global;
607
0
      txStringCStream stream;
608
      
609
0
      mxPush(mxGlobal);
610
0
      global = the->stack;
611
      
612
0
      slot = fxLastProperty(the, fxNewHostObject(the, NULL));
613
0
      slot = fxNextHostFunctionProperty(the, slot, fx_agent_leaving, 0, xsID("leaving"), XS_DONT_ENUM_FLAG); 
614
0
      slot = fxNextHostFunctionProperty(the, slot, fx_agent_monotonicNow, 0, xsID("monotonicNow"), XS_DONT_ENUM_FLAG); 
615
0
      slot = fxNextHostFunctionProperty(the, slot, fx_agent_receiveBroadcast, 1, xsID("receiveBroadcast"), XS_DONT_ENUM_FLAG); 
616
0
      slot = fxNextHostFunctionProperty(the, slot, fx_agent_report, 1, xsID("report"), XS_DONT_ENUM_FLAG); 
617
0
      slot = fxNextHostFunctionProperty(the, slot, fx_agent_sleep, 1, xsID("sleep"), XS_DONT_ENUM_FLAG); 
618
0
      fxSetHostData(the, the->stack, agent);
619
      
620
0
      mxPush(mxObjectPrototype);
621
0
      slot = fxLastProperty(the, fxNewObjectInstance(the));
622
0
      slot = fxNextSlotProperty(the, slot, the->stack + 1, xsID("agent"), XS_GET_ONLY);
623
      
624
0
      slot = fxLastProperty(the, fxToInstance(the, global));
625
0
      slot = fxNextSlotProperty(the, slot, the->stack, xsID("$262"), XS_GET_ONLY);
626
      
627
0
      mxPop();
628
0
      mxPop();
629
0
      mxPop();
630
      
631
0
      stream.buffer = agent->script;
632
0
      stream.offset = 0;
633
0
      stream.size = agent->scriptLength;
634
0
      fxRunScript(the, fxParseScript(the, &stream, fxStringCGetter, mxProgramFlag), mxThis, C_NULL, C_NULL, C_NULL, mxProgram.value.reference);
635
0
      fxRunLoop(the);
636
0
    }
637
0
    xsCatch {
638
0
    }
639
0
  }
640
0
  xsEndHost(the);
641
0
  xsDeleteMachine(machine);
642
#if mxWindows
643
  return 0;
644
#else
645
0
  return NULL;
646
0
#endif
647
0
}
648
649
void fx_createRealm(xsMachine* the)
650
0
{
651
0
  xsResult = xsThis;
652
0
}
653
654
void fx_detachArrayBuffer(xsMachine* the)
655
0
{
656
0
  txSlot* slot = mxArgv(0);
657
0
  if (slot->kind == XS_REFERENCE_KIND) {
658
0
    txSlot* instance = slot->value.reference;
659
0
    if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_ARRAY_BUFFER_KIND) && (instance != mxArrayBufferPrototype.value.reference)) {
660
0
      slot->value.arrayBuffer.address = C_NULL;
661
0
      slot->next->value.bufferInfo.length = 0;
662
0
      return;
663
0
    }
664
0
  }
665
0
  mxTypeError("this is no ArrayBuffer instance");
666
0
}
667
668
/* TIMER */
669
670
static txHostHooks gxTimerHooks = {
671
  fx_destroyTimer,
672
  fx_markTimer
673
};
674
675
void fx_callbackTimer(txSharedTimer* timer, void* refcon, txInteger refconSize)
676
0
{
677
0
  txJob* job = (txJob*)refcon;
678
0
  txMachine* the = job->the;
679
0
  if (the) {
680
0
    fxBeginHost(the);
681
0
    mxTry(the) {
682
0
      mxPushUndefined();
683
0
      mxPush(job->function);
684
0
      mxCall();
685
0
      mxPush(job->argument);
686
0
      mxRunCount(1);
687
0
      mxPop();
688
0
    }
689
0
    mxCatch(the) {
690
0
      *((txSlot*)the->rejection) = mxException;
691
0
      timer->interval = 0;
692
0
    }
693
0
    if (job->the) {
694
0
      if (timer->interval == 0) {
695
0
        fxAccess(the, &job->self);
696
0
        *mxResult = the->scratch;
697
0
        fxForget(the, &job->self);
698
0
        fxSetHostData(the, mxResult, NULL);
699
0
        job->the = NULL;
700
0
      }
701
0
    }
702
0
    else
703
0
      timer->interval = 0;
704
0
    fxEndHost(the);
705
0
  }
706
0
  else
707
0
    timer->interval = 0;
708
0
}
709
710
void fx_clearTimer(txMachine* the)
711
0
{
712
0
  if ((0 == mxArgc) || (XS_REFERENCE_KIND != mxArgv(0)->kind) || (C_NULL == fxGetHostDataIf(the, mxArgv(0))))
713
0
    return;
714
0
  txHostHooks* hooks = fxGetHostHooks(the, mxArgv(0));
715
0
  if (hooks == &gxTimerHooks) {
716
0
    txJob* job = fxGetHostData(the, mxArgv(0));
717
0
    if (job) {
718
0
      fxForget(the, &job->self);
719
0
      fxSetHostData(the, mxArgv(0), NULL);
720
0
      job->the = NULL;
721
0
      txSharedTimer* timer = (txSharedTimer*)(((txByte*)job) - offsetof(txSharedTimer, refcon));
722
0
      fxRescheduleSharedTimer(timer, 0, 0);
723
0
    }
724
0
  }
725
0
}
726
727
void fx_destroyTimer(void* data)
728
0
{
729
0
}
730
731
void fx_markTimer(txMachine* the, void* it, txMarkRoot markRoot)
732
0
{
733
0
  txJob* job = it;
734
0
  if (job) {
735
0
    (*markRoot)(the, &job->function);
736
0
    (*markRoot)(the, &job->argument);
737
0
  }
738
0
}
739
740
void fx_setInterval(txMachine* the)
741
0
{
742
0
  fx_setTimer(the, fxToNumber(the, mxArgv(1)), 1);
743
0
}
744
745
void fx_setTimeout(txMachine* the)
746
0
{
747
0
  fx_setTimer(the, fxToNumber(the, mxArgv(1)), 0);
748
0
}
749
750
void fx_setTimer(txMachine* the, txNumber interval, txBoolean repeat)
751
0
{
752
0
  txJob _job;
753
0
  txJob* job;
754
0
  txSharedTimer* timer;
755
0
  if (c_isnan(interval) || (interval < 0))
756
0
    interval = 0;
757
0
  c_memset(&_job, 0, sizeof(txJob));
758
0
  timer = fxScheduleSharedTimer(interval, (repeat) ? interval : 0, fx_callbackTimer, &_job, sizeof(txJob));  
759
0
  if (!timer)
760
0
    fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
761
0
  job = (txJob*)&(timer->refcon[0]);
762
0
  job->the = the;
763
0
  fxNewHostObject(the, NULL);
764
0
    mxPull(job->self);
765
0
  job->function = *mxArgv(0);
766
0
  if (mxArgc > 2)
767
0
    job->argument = *mxArgv(2);
768
0
  else
769
0
    job->argument = mxUndefined;
770
0
  fxSetHostData(the, &job->self, job);
771
0
  fxSetHostHooks(the, &job->self, &gxTimerHooks);
772
0
  fxRemember(the, &job->self);
773
0
  fxAccess(the, &job->self);
774
0
  *mxResult = the->scratch;
775
0
}
776
777
/* PLATFORM */
778
779
void fxCreateMachinePlatform(txMachine* the)
780
23.2k
{
781
23.2k
#ifdef mxDebug
782
23.2k
  the->connection = mxNoSocket;
783
23.2k
#endif
784
23.2k
}
785
786
void fxDeleteMachinePlatform(txMachine* the)
787
23.2k
{
788
23.2k
}
789
790
void fxQueuePromiseJobs(txMachine* the)
791
96.2k
{
792
96.2k
  the->promiseJobs = 1;
793
96.2k
}
794
795
/* SHARED TIMERS */
796
797
typedef struct sxSharedTimers txSharedTimers;
798
struct sxSharedTimers {
799
  txSharedTimer* first;
800
  txMutex mutex;
801
};
802
static txSharedTimers gxSharedTimers;
803
804
void fxInitializeSharedTimers()
805
23.2k
{
806
23.2k
  c_memset(&gxSharedTimers, 0, sizeof(txSharedTimers));
807
23.2k
  fxCreateMutex(&(gxSharedTimers.mutex));
808
23.2k
}
809
810
void fxTerminateSharedTimers()
811
23.2k
{
812
23.2k
  fxDeleteMutex(&(gxSharedTimers.mutex));
813
23.2k
  if (gxSharedTimers.first != C_NULL) {
814
0
    fprintf(stderr, "# shared timers mismatch!\n");
815
0
    exit(1);
816
0
  }
817
23.2k
}
818
819
void fxRescheduleSharedTimer(txSharedTimer* timer, txNumber timeout, txNumber interval)
820
0
{
821
0
    fxLockMutex(&(gxSharedTimers.mutex));
822
0
  timer->when = mxMonotonicNow() + timeout;
823
0
  timer->interval = interval;
824
0
    fxUnlockMutex(&(gxSharedTimers.mutex));
825
0
}
826
827
void* fxScheduleSharedTimer(txNumber timeout, txNumber interval, txSharedTimerCallback callback, void* refcon, txInteger refconSize)
828
3
{
829
3
  txSharedTimer* timer;
830
3
  txSharedTimer** address;
831
3
  txSharedTimer* link;
832
3
  timer = c_calloc(1, sizeof(txSharedTimer) + refconSize - 1);
833
3
  if (timer) {
834
3
    timer->thread = mxCurrentThread();
835
3
    timer->when = mxMonotonicNow() + timeout;
836
3
    timer->interval = interval;
837
3
    timer->callback = callback;
838
3
    timer->refconSize = refconSize;
839
3
    c_memcpy(timer->refcon, refcon, refconSize);
840
    
841
3
    fxLockMutex(&(gxSharedTimers.mutex));
842
3
    address = (txSharedTimer**)&(gxSharedTimers.first);
843
3
    while ((link = *address))
844
0
      address = &(link->next);
845
3
    *address = timer;
846
3
    fxUnlockMutex(&(gxSharedTimers.mutex));
847
3
    }
848
3
    return timer;
849
3
}
850
851
void fxUnscheduleSharedTimer(txSharedTimer* timer)
852
3
{
853
3
  txSharedTimer** address;
854
3
  txSharedTimer* link;
855
3
    fxLockMutex(&(gxSharedTimers.mutex));
856
3
    address = (txSharedTimer**)&(gxSharedTimers.first);
857
3
  while ((link = *address)) {
858
3
    if (link == timer) {
859
3
      *address = link->next;
860
3
      c_free(timer);
861
3
      break;
862
3
    }
863
0
    address = &(link->next);
864
0
  }
865
3
    fxUnlockMutex(&(gxSharedTimers.mutex));
866
3
}
867
868
void fxRunLoop(txMachine* the)
869
12.8k
{
870
12.8k
  txThread thread = mxCurrentThread();
871
12.8k
  txNumber when;
872
12.8k
  txInteger count;
873
12.8k
  txSharedTimer* timer;
874
  
875
234k
  for (;;) {
876
234k
    fxEndJob(the);
877
234k
    while (the->promiseJobs) {
878
96.2k
      while (the->promiseJobs) {
879
96.0k
        the->promiseJobs = 0;
880
96.0k
        fxRunPromiseJobs(the);
881
96.0k
      }
882
182
      fxEndJob(the);
883
182
    }
884
234k
    when = mxMonotonicNow();
885
234k
    fxLockMutex(&(gxSharedTimers.mutex));
886
234k
    count = 0;
887
234k
    timer = gxSharedTimers.first;
888
456k
    while (timer) {
889
221k
      if (timer->thread == thread) {
890
221k
        count++;
891
221k
        if (timer->when <= when)
892
2
          break; // one timer at time to run promise jobs queued by the timer in the same "tick"
893
221k
      }
894
221k
      timer = timer->next;
895
221k
    }
896
234k
    fxUnlockMutex(&(gxSharedTimers.mutex));
897
234k
    if (timer) {
898
2
      (timer->callback)(timer, timer->refcon, timer->refconSize);
899
2
      if (timer->interval == 0)
900
2
        fxUnscheduleSharedTimer(timer);
901
0
      else
902
0
        timer->when += timer->interval;
903
2
      continue;
904
2
    }
905
234k
    if (count == 0)
906
12.8k
      break;
907
234k
  }
908
12.8k
}
909
910
void fxFulfillModuleFile(txMachine* the)
911
0
{
912
0
}
913
914
void fxRejectModuleFile(txMachine* the)
915
0
{
916
0
  *((txSlot*)the->rejection) = xsArg(0);
917
0
}
918
919
void fxRunModuleFile(txMachine* the, txString path)
920
0
{
921
0
  txSlot* realm = mxProgram.value.reference->next->value.module.realm;
922
0
  mxPushStringC(path);
923
0
  mxPushUndefined();
924
0
  fxRunImport(the, realm, C_NULL);
925
0
  mxDub();
926
0
  fxGetID(the, mxID(_then));
927
0
  mxCall();
928
0
  fxNewHostFunction(the, fxFulfillModuleFile, 1, XS_NO_ID, XS_NO_ID);
929
0
  fxNewHostFunction(the, fxRejectModuleFile, 1, XS_NO_ID, XS_NO_ID);
930
0
  mxRunCount(2);
931
0
  mxPop();
932
0
}
933
934
void fxRunProgramFile(txMachine* the, txString path, txUnsigned flags)
935
0
{
936
0
  txSlot* realm = mxProgram.value.reference->next->value.module.realm;
937
0
  txScript* script = fxLoadScript(the, path, flags);
938
0
  mxModuleInstanceInternal(mxProgram.value.reference)->value.module.id = fxID(the, path);
939
0
  fxRunScript(the, script, mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, mxProgram.value.reference);
940
0
  mxPullSlot(mxResult);
941
0
}
942
943
void fxAbort(txMachine* the, int status)
944
979
{
945
979
  if (XS_DEBUGGER_EXIT == status)
946
0
    c_exit(1);
947
979
  if (the->exitStatus) // xsEndHost calls fxAbort!
948
0
    return;
949
979
  the->exitStatus = status;
950
979
  fxExitToHost(the);
951
979
}
952
953
txID fxFindModule(txMachine* the, txSlot* realm, txID moduleID, txSlot* slot)
954
19.7k
{
955
19.7k
  char name[C_PATH_MAX];
956
19.7k
  char path[C_PATH_MAX];
957
19.7k
  txInteger dot = 0;
958
19.7k
  txString slash;
959
19.7k
  fxToStringBuffer(the, slot, name, sizeof(name));
960
19.7k
  if (name[0] == '.') {
961
4
    if (name[1] == '/') {
962
1
      dot = 1;
963
1
    }
964
3
    else if ((name[1] == '.') && (name[2] == '/')) {
965
0
      dot = 2;
966
0
    }
967
4
  }
968
19.7k
  if (dot) {
969
1
    if (moduleID == XS_NO_ID)
970
0
      return XS_NO_ID;
971
1
    c_strncpy(path, fxGetKeyName(the, moduleID), C_PATH_MAX - 1);
972
1
    path[C_PATH_MAX - 1] = 0;
973
1
    slash = c_strrchr(path, mxSeparator);
974
1
    if (!slash)
975
1
      return XS_NO_ID;
976
0
    if (dot == 2) {
977
0
      *slash = 0;
978
0
      slash = c_strrchr(path, mxSeparator);
979
0
      if (!slash)
980
0
        return XS_NO_ID;
981
0
    }
982
#if mxWindows
983
    {
984
      char c;
985
      char* s = name;
986
      while ((c = *s)) {
987
        if (c == '/')
988
          *s = '\\';
989
        s++;
990
      }
991
    }
992
#endif
993
0
  }
994
19.7k
  else
995
19.7k
    slash = path;
996
19.7k
  *slash = 0;
997
19.7k
  if ((c_strlen(path) + c_strlen(name + dot)) >= sizeof(path))
998
0
    xsRangeError("path too long");
999
19.7k
  c_strcat(path, name + dot);
1000
19.7k
  return fxNewNameC(the, path);
1001
19.7k
}
1002
1003
void fxLoadModule(txMachine* the, txSlot* module, txID moduleID)
1004
107
{
1005
107
  char path[C_PATH_MAX];
1006
107
  char real[C_PATH_MAX];
1007
107
  txString dot;
1008
107
  txScript* script;
1009
107
#ifdef mxDebug
1010
107
  txUnsigned flags = mxDebugFlag;
1011
#else
1012
  txUnsigned flags = 0;
1013
#endif
1014
107
  c_strncpy(path, fxGetKeyName(the, moduleID), C_PATH_MAX - 1);
1015
107
  path[C_PATH_MAX - 1] = 0;
1016
107
  if (c_realpath(path, real)) {
1017
#if mxWindows
1018
    DWORD attributes;
1019
    attributes = GetFileAttributes(path);
1020
    if (attributes != 0xFFFFFFFF) {
1021
      if (attributes & FILE_ATTRIBUTE_DIRECTORY)
1022
        return;
1023
    }
1024
#else
1025
0
    struct stat a_stat;
1026
0
    if (stat(path, &a_stat) == 0) {
1027
0
      if (S_ISDIR(a_stat.st_mode)) 
1028
0
        return;
1029
0
    }
1030
0
#endif  
1031
0
    dot = c_strrchr(real, '.');
1032
0
    if (dot && !c_strcmp(dot, ".json"))
1033
0
      flags |= mxJSONModuleFlag;
1034
0
    script = fxLoadScript(the, real, flags);
1035
0
    if (script)
1036
0
      fxResolveModule(the, module, moduleID, script, C_NULL, C_NULL);
1037
0
  }
1038
107
}
1039
1040
txScript* fxLoadScript(txMachine* the, txString path, txUnsigned flags)
1041
0
{
1042
0
  txParser _parser;
1043
0
  txParser* parser = &_parser;
1044
0
  txParserJump jump;
1045
0
  FILE* file = NULL;
1046
0
  txString name = NULL;
1047
0
  char map[C_PATH_MAX];
1048
0
  txScript* script = NULL;
1049
0
  fxInitializeParser(parser, the, the->parserBufferSize, the->parserTableModulo);
1050
0
  parser->firstJump = &jump;
1051
0
  file = fopen(path, "r");
1052
0
  if (c_setjmp(jump.jmp_buf) == 0) {
1053
0
    mxParserThrowElse(file);
1054
0
    parser->path = fxNewParserSymbol(parser, path);
1055
0
    fxParserTree(parser, file, (txGetter)fgetc, flags, &name);
1056
0
    fclose(file);
1057
0
    file = NULL;
1058
0
    if (name) {
1059
0
      mxParserThrowElse(c_realpath(fxCombinePath(parser, path, name), map));
1060
0
      parser->path = fxNewParserSymbol(parser, map);
1061
0
      file = fopen(map, "r");
1062
0
      mxParserThrowElse(file);
1063
0
      fxParserSourceMap(parser, file, (txGetter)fgetc, flags, &name);
1064
0
      fclose(file);
1065
0
      file = NULL;
1066
0
      if ((parser->errorCount == 0) && name) {
1067
0
        mxParserThrowElse(c_realpath(fxCombinePath(parser, map, name), map));
1068
0
        parser->path = fxNewParserSymbol(parser, map);
1069
0
      }
1070
0
    }
1071
0
    fxParserHoist(parser);
1072
0
    fxParserBind(parser);
1073
0
    script = fxParserCode(parser);
1074
0
  }
1075
0
  if (file)
1076
0
    fclose(file);
1077
#ifdef mxInstrument
1078
  if (the->peakParserSize < parser->total)
1079
    the->peakParserSize = parser->total;
1080
#endif
1081
0
  fxTerminateParser(parser);
1082
0
  return script;
1083
0
}
1084
1085
/* DEBUG */
1086
1087
#ifdef mxDebug
1088
1089
void fxConnect(txMachine* the)
1090
23.2k
{
1091
23.2k
  if (!c_strcmp(the->name, "xst_fuzz"))
1092
0
    return;
1093
23.2k
  if (!c_strcmp(the->name, "xst_fuzz_oss"))
1094
23.2k
    return;
1095
#ifdef mxMultipleThreads
1096
  if (!c_strcmp(the->name, "xst262"))
1097
    return;
1098
  if (!c_strcmp(the->name, "xst-agent"))
1099
    return;
1100
#endif    
1101
0
  char name[256];
1102
0
  char* colon;
1103
0
  int port;
1104
#if mxWindows
1105
  if (GetEnvironmentVariable("XSBUG_HOST", name, sizeof(name))) {
1106
#else
1107
0
  colon = getenv("XSBUG_HOST");
1108
0
  if ((colon) && (c_strlen(colon) + 1 < sizeof(name))) {
1109
0
    c_strcpy(name, colon);
1110
0
#endif    
1111
0
    colon = strchr(name, ':');
1112
0
    if (colon == NULL)
1113
0
      port = 5002;
1114
0
    else {
1115
0
      *colon = 0;
1116
0
      colon++;
1117
0
      port = strtol(colon, NULL, 10);
1118
0
    }
1119
0
  }
1120
0
  else {
1121
0
    strcpy(name, "localhost");
1122
0
    port = 5002;
1123
0
  }
1124
#if mxWindows
1125
{   
1126
  WSADATA wsaData;
1127
  struct hostent *host;
1128
  struct sockaddr_in address;
1129
  unsigned long flag;
1130
  if (WSAStartup(0x202, &wsaData) == SOCKET_ERROR)
1131
    return;
1132
  host = gethostbyname(name);
1133
  if (!host)
1134
    goto bail;
1135
  memset(&address, 0, sizeof(address));
1136
  address.sin_family = AF_INET;
1137
  memcpy(&(address.sin_addr), host->h_addr, host->h_length);
1138
    address.sin_port = htons(port);
1139
  the->connection = socket(AF_INET, SOCK_STREAM, 0);
1140
  if (the->connection == INVALID_SOCKET)
1141
    return;
1142
    flag = 1;
1143
    ioctlsocket(the->connection, FIONBIO, &flag);
1144
  if (connect(the->connection, (struct sockaddr*)&address, sizeof(address)) == SOCKET_ERROR) {
1145
    if (WSAEWOULDBLOCK == WSAGetLastError()) {
1146
      fd_set fds;
1147
      struct timeval timeout = { 2, 0 }; // 2 seconds, 0 micro-seconds
1148
      FD_ZERO(&fds);
1149
      FD_SET(the->connection, &fds);
1150
      if (select(0, NULL, &fds, NULL, &timeout) == 0)
1151
        goto bail;
1152
      if (!FD_ISSET(the->connection, &fds))
1153
        goto bail;
1154
    }
1155
    else
1156
      goto bail;
1157
  }
1158
  flag = 0;
1159
  ioctlsocket(the->connection, FIONBIO, &flag);
1160
}
1161
#else
1162
0
{   
1163
0
  struct sockaddr_in address;
1164
0
  int flag;
1165
0
  memset(&address, 0, sizeof(address));
1166
0
    address.sin_family = AF_INET;
1167
0
  address.sin_addr.s_addr = inet_addr(name);
1168
0
  if (address.sin_addr.s_addr == INADDR_NONE) {
1169
0
    struct hostent *host = gethostbyname(name);
1170
0
    if (!host)
1171
0
      return;
1172
0
    memcpy(&(address.sin_addr), host->h_addr, host->h_length);
1173
0
  }
1174
0
    address.sin_port = htons(port);
1175
0
  the->connection = socket(AF_INET, SOCK_STREAM, 0);
1176
0
  if (the->connection <= 0)
1177
0
    goto bail;
1178
0
  c_signal(SIGPIPE, SIG_IGN);
1179
#if mxMacOSX
1180
  {
1181
    int set = 1;
1182
    setsockopt(the->connection, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
1183
  }
1184
#endif
1185
0
  flag = fcntl(the->connection, F_GETFL, 0);
1186
0
  fcntl(the->connection, F_SETFL, flag | O_NONBLOCK);
1187
0
  if (connect(the->connection, (struct sockaddr*)&address, sizeof(address)) < 0) {
1188
0
       if (errno == EINPROGRESS) { 
1189
0
      fd_set fds;
1190
0
      struct timeval timeout = { 2, 0 }; // 2 seconds, 0 micro-seconds
1191
0
      int error = 0;
1192
0
      unsigned int length = sizeof(error);
1193
0
      FD_ZERO(&fds);
1194
0
      FD_SET(the->connection, &fds);
1195
0
      if (select(the->connection + 1, NULL, &fds, NULL, &timeout) == 0)
1196
0
        goto bail;
1197
0
      if (!FD_ISSET(the->connection, &fds))
1198
0
        goto bail;
1199
0
      if (getsockopt(the->connection, SOL_SOCKET, SO_ERROR, &error, &length) < 0)
1200
0
        goto bail;
1201
0
      if (error)
1202
0
        goto bail;
1203
0
    }
1204
0
    else
1205
0
      goto bail;
1206
0
  }
1207
0
  fcntl(the->connection, F_SETFL, flag);
1208
0
  c_signal(SIGPIPE, SIG_DFL);
1209
0
}
1210
0
#endif
1211
0
  return;
1212
0
bail:
1213
0
  fxDisconnect(the);
1214
0
}
1215
1216
void fxDisconnect(txMachine* the)
1217
0
{
1218
#if mxWindows
1219
  if (the->connection != INVALID_SOCKET) {
1220
    closesocket(the->connection);
1221
    the->connection = INVALID_SOCKET;
1222
  }
1223
  WSACleanup();
1224
#else
1225
0
  if (the->connection >= 0) {
1226
0
    close(the->connection);
1227
0
    the->connection = -1;
1228
0
  }
1229
0
#endif
1230
0
}
1231
1232
txBoolean fxIsConnected(txMachine* the)
1233
7.28M
{
1234
7.28M
  return (the->connection != mxNoSocket) ? 1 : 0;
1235
7.28M
}
1236
1237
txBoolean fxIsReadable(txMachine* the)
1238
89.9M
{
1239
89.9M
  return 0;
1240
89.9M
}
1241
1242
void fxReceive(txMachine* the)
1243
0
{
1244
0
  int count;
1245
0
  if (the->connection != mxNoSocket) {
1246
#if mxWindows
1247
    count = recv(the->connection, the->debugBuffer, sizeof(the->debugBuffer) - 1, 0);
1248
    if (count < 0)
1249
      fxDisconnect(the);
1250
    else
1251
      the->debugOffset = count;
1252
#else
1253
0
  again:
1254
0
    count = read(the->connection, the->debugBuffer, sizeof(the->debugBuffer) - 1);
1255
0
    if (count < 0) {
1256
0
      if (errno == EINTR)
1257
0
        goto again;
1258
0
      else
1259
0
        fxDisconnect(the);
1260
0
    }
1261
0
    else
1262
0
      the->debugOffset = count;
1263
0
#endif
1264
0
  }
1265
0
  the->debugBuffer[the->debugOffset] = 0;
1266
0
}
1267
1268
void fxSend(txMachine* the, txBoolean more)
1269
0
{
1270
0
  if (the->connection != mxNoSocket) {
1271
#if mxWindows
1272
    if (send(the->connection, the->echoBuffer, the->echoOffset, 0) <= 0)
1273
      fxDisconnect(the);
1274
#else
1275
0
  again:
1276
0
    if (write(the->connection, the->echoBuffer, the->echoOffset) <= 0) {
1277
0
      if (errno == EINTR)
1278
0
        goto again;
1279
0
      else
1280
0
        fxDisconnect(the);
1281
0
    }
1282
0
#endif
1283
0
  }
1284
0
}
1285
1286
#endif /* mxDebug */
1287
1288
1289
1290
1291