Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F4468021
navigator.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
navigator.c
View Options
#include
<compat.h>
// IWYU pragma: keep
#include
<stdlib.h>
#include
<stdio.h>
#include
<string.h>
#include
<uthash.h>
#ifdef __APPLE__
#include
<sys/sysctl.h>
#elif defined(__linux__)
#include
<sys/sysinfo.h>
#endif
#include
"ant.h"
#include
"errors.h"
#include
"runtime.h"
#include
"internal.h"
#include
"silver/engine.h"
#include
"modules/navigator.h"
#include
"modules/symbol.h"
#include
"gc/modules.h"
typedef
enum
{
LOCK_MODE_EXCLUSIVE
,
LOCK_MODE_SHARED
}
lock_mode_t
;
typedef
struct
lock_entry
{
char
*
name
;
lock_mode_t
mode
;
int
shared_count
;
UT_hash_handle
hh
;
}
lock_entry_t
;
typedef
struct
lock_request
{
ant_t
*
js
;
char
*
name
;
lock_mode_t
mode
;
ant_value_t
callback
;
ant_value_t
promise
;
struct
lock_request
*
next
;
}
lock_request_t
;
static
lock_entry_t
*
locks
=
NULL
;
static
lock_request_t
*
pending_requests
=
NULL
;
static
int
get_hardware_concurrency
(
void
)
{
#ifdef __APPLE__
int
count
;
size_t
size
=
sizeof
(
count
);
if
(
sysctlbyname
(
"hw.ncpu"
,
&
count
,
&
size
,
NULL
,
0
)
==
0
)
{
return
count
;
}
return
1
;
#elif defined(__linux__)
int
count
=
(
int
)
sysconf
(
_SC_NPROCESSORS_ONLN
);
return
count
>
0
?
count
:
1
;
#elif defined(_WIN32) || defined(_WIN64)
SYSTEM_INFO
sysinfo
;
GetSystemInfo
(
&
sysinfo
);
return
(
int
)
sysinfo
.
dwNumberOfProcessors
;
#else
return
1
;
#endif
}
static
const
char
*
get_platform_string
(
void
)
{
#if defined(__APPLE__)
return
"MacIntel"
;
#elif defined(__linux__)
return
"Linux x86_64"
;
#elif defined(_WIN32) || defined(_WIN64)
return
"Win32"
;
#elif defined(__FreeBSD__)
return
"FreeBSD"
;
#else
return
"Unknown"
;
#endif
}
static
lock_entry_t
*
find_lock
(
const
char
*
name
)
{
lock_entry_t
*
entry
=
NULL
;
HASH_FIND_STR
(
locks
,
name
,
entry
);
return
entry
;
}
static
lock_entry_t
*
create_lock
(
const
char
*
name
,
lock_mode_t
mode
)
{
lock_entry_t
*
entry
=
calloc
(
1
,
sizeof
(
lock_entry_t
));
if
(
!
entry
)
return
NULL
;
entry
->
name
=
strdup
(
name
);
entry
->
mode
=
mode
;
entry
->
shared_count
=
(
mode
==
LOCK_MODE_SHARED
)
?
1
:
0
;
HASH_ADD_STR
(
locks
,
name
,
entry
);
return
entry
;
}
static
bool
can_acquire_lock
(
const
char
*
name
,
lock_mode_t
mode
)
{
lock_entry_t
*
entry
=
find_lock
(
name
);
if
(
!
entry
)
return
true
;
if
(
mode
==
LOCK_MODE_SHARED
&&
entry
->
mode
==
LOCK_MODE_SHARED
)
return
true
;
return
false
;
}
static
void
release_lock
(
const
char
*
name
)
{
lock_entry_t
*
entry
=
find_lock
(
name
);
if
(
!
entry
)
return
;
if
(
entry
->
mode
==
LOCK_MODE_SHARED
)
{
entry
->
shared_count
--
;
if
(
entry
->
shared_count
>
0
)
return
;
}
HASH_DEL
(
locks
,
entry
);
free
(
entry
->
name
);
free
(
entry
);
}
static
void
process_pending_requests
(
ant_t
*
js
);
static
ant_value_t
make_lock_handler
(
ant_t
*
js
,
ant_value_t
cfunc
,
ant_value_t
lock_name
,
ant_value_t
outer_promise
)
{
ant_value_t
fn_obj
=
js_mkobj
(
js
);
ant_value_t
data_obj
=
js_mkobj
(
js
);
js_set
(
js
,
data_obj
,
"lockName"
,
lock_name
);
js_set
(
js
,
data_obj
,
"outerPromise"
,
outer_promise
);
js_set_slot
(
fn_obj
,
SLOT_DATA
,
data_obj
);
js_set_slot
(
fn_obj
,
SLOT_CFUNC
,
cfunc
);
return
js_obj_to_func
(
fn_obj
);
}
static
ant_value_t
lock_then_handler
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
current_func
=
js_getcurrentfunc
(
js
);
ant_value_t
data_obj
=
js_get_slot
(
current_func
,
SLOT_DATA
);
ant_value_t
lock_name_val
=
js_get
(
js
,
data_obj
,
"lockName"
);
ant_value_t
outer_promise
=
js_get
(
js
,
data_obj
,
"outerPromise"
);
ant_value_t
result_val
=
(
nargs
>
0
)
?
args
[
0
]
:
js_mkundef
();
size_t
name_len
;
char
*
name
=
js_getstr
(
js
,
lock_name_val
,
&
name_len
);
if
(
name
)
release_lock
(
name
);
js_resolve_promise
(
js
,
outer_promise
,
result_val
);
process_pending_requests
(
js
);
return
js_mkundef
();
}
static
ant_value_t
lock_catch_handler
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
current_func
=
js_getcurrentfunc
(
js
);
ant_value_t
data_obj
=
js_get_slot
(
current_func
,
SLOT_DATA
);
ant_value_t
lock_name_val
=
js_get
(
js
,
data_obj
,
"lockName"
);
ant_value_t
outer_promise
=
js_get
(
js
,
data_obj
,
"outerPromise"
);
ant_value_t
error_val
=
(
nargs
>
0
)
?
args
[
0
]
:
js_mkundef
();
size_t
name_len
;
char
*
name
=
js_getstr
(
js
,
lock_name_val
,
&
name_len
);
if
(
name
)
release_lock
(
name
);
js_reject_promise
(
js
,
outer_promise
,
error_val
);
process_pending_requests
(
js
);
return
js_mkundef
();
}
static
void
execute_lock_callback
(
ant_t
*
js
,
const
char
*
name
,
lock_mode_t
mode
,
ant_value_t
callback
,
ant_value_t
outer_promise
)
{
ant_value_t
lock_obj
=
js_mkobj
(
js
);
js_set
(
js
,
lock_obj
,
"name"
,
js_mkstr
(
js
,
name
,
strlen
(
name
)));
js_set
(
js
,
lock_obj
,
"mode"
,
js_mkstr
(
js
,
mode
==
LOCK_MODE_EXCLUSIVE
?
"exclusive"
:
"shared"
,
mode
==
LOCK_MODE_EXCLUSIVE
?
9
:
6
));
js_set_sym
(
js
,
lock_obj
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"Lock"
,
4
));
ant_value_t
result
=
sv_vm_call
(
js
->
vm
,
js
,
callback
,
js_mkundef
(),
&
lock_obj
,
1
,
NULL
,
false
);
if
(
vtype
(
result
)
==
T_ERR
)
{
release_lock
(
name
);
js_reject_promise
(
js
,
outer_promise
,
result
);
process_pending_requests
(
js
);
return
;
}
if
(
vtype
(
result
)
==
T_PROMISE
)
{
ant_value_t
name_str
=
js_mkstr
(
js
,
name
,
strlen
(
name
));
ant_value_t
on_resolve
=
make_lock_handler
(
js
,
js_mkfun
(
lock_then_handler
),
name_str
,
outer_promise
);
ant_value_t
on_reject
=
make_lock_handler
(
js
,
js_mkfun
(
lock_catch_handler
),
name_str
,
outer_promise
);
js_promise_then
(
js
,
result
,
on_resolve
,
on_reject
);
return
;
}
release_lock
(
name
);
js_resolve_promise
(
js
,
outer_promise
,
result
);
process_pending_requests
(
js
);
}
static
void
process_pending_requests
(
ant_t
*
js
)
{
lock_request_t
*
prev
=
NULL
;
lock_request_t
*
req
=
pending_requests
;
while
(
req
)
{
if
(
can_acquire_lock
(
req
->
name
,
req
->
mode
))
{
lock_entry_t
*
entry
=
find_lock
(
req
->
name
);
if
(
entry
&&
entry
->
mode
==
LOCK_MODE_SHARED
&&
req
->
mode
==
LOCK_MODE_SHARED
)
{
entry
->
shared_count
++
;
}
else
{
create_lock
(
req
->
name
,
req
->
mode
);
}
lock_request_t
*
to_process
=
req
;
if
(
prev
)
{
prev
->
next
=
req
->
next
;
}
else
{
pending_requests
=
req
->
next
;
}
req
=
req
->
next
;
execute_lock_callback
(
js
,
to_process
->
name
,
to_process
->
mode
,
to_process
->
callback
,
to_process
->
promise
);
free
(
to_process
->
name
);
free
(
to_process
);
return
;
}
else
{
prev
=
req
;
req
=
req
->
next
;
}
}
}
static
ant_value_t
locks_request
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
{
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"locks.request requires at least 2 arguments"
);
}
size_t
name_len
;
char
*
name
=
js_getstr
(
js
,
args
[
0
],
&
name_len
);
if
(
!
name
)
{
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"First argument must be a string"
);
}
ant_value_t
options
=
js_mkundef
();
ant_value_t
callback
;
lock_mode_t
mode
=
LOCK_MODE_EXCLUSIVE
;
bool
if_available
=
false
;
if
(
nargs
==
2
)
{
callback
=
args
[
1
];
}
else
{
options
=
args
[
1
];
callback
=
args
[
2
];
if
(
is_special_object
(
options
))
{
ant_value_t
mode_val
=
js_get
(
js
,
options
,
"mode"
);
if
(
vtype
(
mode_val
)
==
T_STR
)
{
size_t
mode_len
;
char
*
mode_str
=
js_getstr
(
js
,
mode_val
,
&
mode_len
);
if
(
mode_str
&&
strcmp
(
mode_str
,
"shared"
)
==
0
)
mode
=
LOCK_MODE_SHARED
;
}
if
(
js_get
(
js
,
options
,
"ifAvailable"
)
==
js_true
)
if_available
=
true
;
}
}
if
(
vtype
(
callback
)
!=
T_FUNC
)
{
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"Callback must be a function"
);
}
ant_value_t
promise
=
js_mkpromise
(
js
);
if
(
if_available
&&
!
can_acquire_lock
(
name
,
mode
))
{
ant_value_t
null_val
=
js_mknull
();
ant_value_t
result
=
sv_vm_call
(
js
->
vm
,
js
,
callback
,
js_mkundef
(),
&
null_val
,
1
,
NULL
,
false
);
if
(
vtype
(
result
)
==
T_PROMISE
)
{
ant_value_t
on_resolve
=
make_lock_handler
(
js
,
js_mkfun
(
lock_then_handler
),
js_mkstr
(
js
,
""
,
0
),
promise
);
js_promise_then
(
js
,
result
,
on_resolve
,
js_mkundef
());
return
promise
;
}
js_resolve_promise
(
js
,
promise
,
result
);
return
promise
;
}
if
(
can_acquire_lock
(
name
,
mode
))
{
lock_entry_t
*
entry
=
find_lock
(
name
);
if
(
entry
&&
entry
->
mode
==
LOCK_MODE_SHARED
&&
mode
==
LOCK_MODE_SHARED
)
{
entry
->
shared_count
++
;
}
else
{
create_lock
(
name
,
mode
);
}
execute_lock_callback
(
js
,
name
,
mode
,
callback
,
promise
);
}
else
{
lock_request_t
*
req
=
calloc
(
1
,
sizeof
(
lock_request_t
));
req
->
js
=
js
;
req
->
name
=
strdup
(
name
);
req
->
mode
=
mode
;
req
->
callback
=
callback
;
req
->
promise
=
promise
;
req
->
next
=
NULL
;
lock_request_t
*
tail
=
pending_requests
;
if
(
!
tail
)
{
pending_requests
=
req
;
}
else
{
while
(
tail
->
next
)
tail
=
tail
->
next
;
tail
->
next
=
req
;
}
}
return
promise
;
}
static
ant_value_t
locks_query
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
ant_value_t
result
=
js_mkobj
(
js
);
ant_value_t
held_arr
=
js_mkarr
(
js
);
ant_value_t
pending_arr
=
js_mkarr
(
js
);
lock_entry_t
*
entry
,
*
tmp
;
HASH_ITER
(
hh
,
locks
,
entry
,
tmp
)
{
ant_value_t
lock_info
=
js_mkobj
(
js
);
js_set
(
js
,
lock_info
,
"name"
,
js_mkstr
(
js
,
entry
->
name
,
strlen
(
entry
->
name
)));
js_set
(
js
,
lock_info
,
"mode"
,
js_mkstr
(
js
,
entry
->
mode
==
LOCK_MODE_EXCLUSIVE
?
"exclusive"
:
"shared"
,
entry
->
mode
==
LOCK_MODE_EXCLUSIVE
?
9
:
6
));
js_arr_push
(
js
,
held_arr
,
lock_info
);
}
lock_request_t
*
req
=
pending_requests
;
while
(
req
)
{
ant_value_t
req_info
=
js_mkobj
(
js
);
js_set
(
js
,
req_info
,
"name"
,
js_mkstr
(
js
,
req
->
name
,
strlen
(
req
->
name
)));
js_set
(
js
,
req_info
,
"mode"
,
js_mkstr
(
js
,
req
->
mode
==
LOCK_MODE_EXCLUSIVE
?
"exclusive"
:
"shared"
,
req
->
mode
==
LOCK_MODE_EXCLUSIVE
?
9
:
6
));
js_arr_push
(
js
,
pending_arr
,
req_info
);
req
=
req
->
next
;
}
js_set
(
js
,
result
,
"held"
,
held_arr
);
js_set
(
js
,
result
,
"pending"
,
pending_arr
);
ant_value_t
promise
=
js_mkpromise
(
js
);
js_resolve_promise
(
js
,
promise
,
result
);
return
promise
;
}
void
init_navigator_module
(
void
)
{
ant_t
*
js
=
rt
->
js
;
ant_value_t
navigator_obj
=
js_mkobj
(
js
);
js_set
(
js
,
navigator_obj
,
"hardwareConcurrency"
,
js_mknum
((
double
)
get_hardware_concurrency
()));
js_set
(
js
,
navigator_obj
,
"language"
,
js_mkstr
(
js
,
"en-US"
,
5
));
ant_value_t
languages_arr
=
js_mkarr
(
js
);
js_arr_push
(
js
,
languages_arr
,
js_mkstr
(
js
,
"en-US"
,
5
));
js_set
(
js
,
navigator_obj
,
"languages"
,
languages_arr
);
const
char
*
platform
=
get_platform_string
();
js_set
(
js
,
navigator_obj
,
"platform"
,
js_mkstr
(
js
,
platform
,
strlen
(
platform
)));
char
user_agent
[
64
];
snprintf
(
user_agent
,
sizeof
(
user_agent
),
"Ant/%s"
,
ANT_VERSION
);
js_set
(
js
,
navigator_obj
,
"userAgent"
,
js_mkstr
(
js
,
user_agent
,
strlen
(
user_agent
)));
ant_value_t
locks_obj
=
js_mkobj
(
js
);
js_set
(
js
,
locks_obj
,
"request"
,
js_mkfun
(
locks_request
));
js_set
(
js
,
locks_obj
,
"query"
,
js_mkfun
(
locks_query
));
js_set_sym
(
js
,
locks_obj
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"LockManager"
,
11
));
js_set
(
js
,
navigator_obj
,
"locks"
,
locks_obj
);
js_set_sym
(
js
,
navigator_obj
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"Navigator"
,
9
));
js_set
(
js
,
js_glob
(
js
),
"navigator"
,
navigator_obj
);
}
void
gc_mark_navigator
(
ant_t
*
js
,
gc_mark_fn
mark
)
{
for
(
lock_request_t
*
req
=
pending_requests
;
req
;
req
=
req
->
next
)
{
mark
(
js
,
req
->
callback
);
mark
(
js
,
req
->
promise
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, May 2, 7:33 PM (1 d, 22 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
541646
Default Alt Text
navigator.c (11 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment