Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 82 additions & 66 deletions spec/std/concurrent/select_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -253,19 +253,23 @@ describe "select" do
end
end

it "raises if channel was closed" do
ch = Channel(String).new

spawn_and_check(->{ ch.close }) do |w|
begin
select
when m = ch.receive
{% if flag?(:win32) && flag?(:aarch64) %}
pending "raises if channel was closed"
{% else %}
it "raises if channel was closed" do
ch = Channel(String).new

spawn_and_check(->{ ch.close }) do |w|
begin
select
when m = ch.receive
end
rescue Channel::ClosedError
w.check
end
rescue Channel::ClosedError
w.check
end
end
end
{% end %}
end

context "non-blocking raise-on-close single-channel" do
Expand Down Expand Up @@ -295,20 +299,24 @@ describe "select" do
end
end

it "raises if channel was closed" do
ch = Channel(String).new
{% if flag?(:win32) && flag?(:aarch64) %}
pending "raises if channel was closed"
{% else %}
it "raises if channel was closed" do
ch = Channel(String).new

spawn_and_check(->{ ch.close }) do |w|
begin
select
when m = ch.receive
else
spawn_and_check(->{ ch.close }) do |w|
begin
select
when m = ch.receive
else
end
rescue Channel::ClosedError
w.check
end
rescue Channel::ClosedError
w.check
end
end
end
{% end %}
end

context "blocking raise-on-close multi-channel" do
Expand Down Expand Up @@ -342,37 +350,41 @@ describe "select" do
end
end

it "raises if channel was closed (1)" do
ch = Channel(String).new
ch2 = Channel(Bool).new
{% if flag?(:win32) && flag?(:aarch64) %}
pending "raises if channel was closed"
{% else %}
it "raises if channel was closed (1)" do
ch = Channel(String).new
ch2 = Channel(Bool).new

spawn_and_check(->{ ch.close }) do |w|
begin
select
when m = ch.receive
when m = ch2.receive
spawn_and_check(->{ ch.close }) do |w|
begin
select
when m = ch.receive
when m = ch2.receive
end
rescue Channel::ClosedError
w.check
end
rescue Channel::ClosedError
w.check
end
end
end

it "raises if channel was closed (2)" do
ch = Channel(String).new
ch2 = Channel(Bool).new
it "raises if channel was closed (2)" do
ch = Channel(String).new
ch2 = Channel(Bool).new

spawn_and_check(->{ ch2.close }) do |w|
begin
select
when m = ch.receive
when m = ch2.receive
spawn_and_check(->{ ch2.close }) do |w|
begin
select
when m = ch.receive
when m = ch2.receive
end
rescue Channel::ClosedError
w.check
end
rescue Channel::ClosedError
w.check
end
end
end
{% end %}
end

context "non-blocking raise-on-close multi-channel" do
Expand Down Expand Up @@ -422,39 +434,43 @@ describe "select" do
end
end

it "raises if channel was closed (1)" do
ch = Channel(String).new
ch2 = Channel(Bool).new
{% if flag?(:win32) && flag?(:aarch64) %}
pending "raises if channel was closed"
{% else %}
it "raises if channel was closed (1)" do
ch = Channel(String).new
ch2 = Channel(Bool).new

spawn_and_check(->{ ch.close }) do |w|
begin
select
when m = ch.receive
when m = ch2.receive
else
spawn_and_check(->{ ch.close }) do |w|
begin
select
when m = ch.receive
when m = ch2.receive
else
end
rescue Channel::ClosedError
w.check
end
rescue Channel::ClosedError
w.check
end
end
end

it "raises if channel was closed (2)" do
ch = Channel(String).new
ch2 = Channel(Bool).new
it "raises if channel was closed (2)" do
ch = Channel(String).new
ch2 = Channel(Bool).new

spawn_and_check(->{ ch2.close }) do |w|
begin
select
when m = ch.receive
when m = ch2.receive
else
spawn_and_check(->{ ch2.close }) do |w|
begin
select
when m = ch.receive
when m = ch2.receive
else
end
rescue Channel::ClosedError
w.check
end
rescue Channel::ClosedError
w.check
end
end
end
{% end %}
end

context "blocking nil-on-close single-channel" do
Expand Down
14 changes: 11 additions & 3 deletions src/exception/call_stack/stackwalk.cr
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ struct Exception::CallStack
{% elsif flag?(:i386) %}
# TODO: use WOW64_CONTEXT in place of CONTEXT
{% raise "x86 not supported" %}
{% elsif flag?(:aarch64) %}
LibC::IMAGE_FILE_MACHINE_ARM64
{% else %}
{% raise "Architecture not supported" %}
{% end %}
Expand All @@ -102,9 +104,15 @@ struct Exception::CallStack
stack_frame.addrFrame.mode = LibC::ADDRESS_MODE::AddrModeFlat
stack_frame.addrStack.mode = LibC::ADDRESS_MODE::AddrModeFlat

stack_frame.addrPC.offset = context.value.rip
stack_frame.addrFrame.offset = context.value.rbp
stack_frame.addrStack.offset = context.value.rsp
{% if flag?(:x86_64) %}
stack_frame.addrPC.offset = context.value.rip
stack_frame.addrFrame.offset = context.value.rbp
stack_frame.addrStack.offset = context.value.rsp
{% elsif flag?(:aarch64) %}
stack_frame.addrPC.offset = context.value.pc
stack_frame.addrFrame.offset = context.value.x[29]
stack_frame.addrStack.offset = context.value.sp
{% end %}

last_frame = nil
cur_proc = LibC.GetCurrentProcess
Expand Down
1 change: 1 addition & 0 deletions src/lib_c/aarch64-windows-msvc
1 change: 1 addition & 0 deletions src/lib_c/x86_64-windows-msvc/c/dbghelp.cr
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ lib LibC
end

IMAGE_FILE_MACHINE_AMD64 = DWORD.new!(0x8664)
IMAGE_FILE_MACHINE_ARM64 = DWORD.new!(0xAA64)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: This const value is a neat gimmick. 😆


alias PREAD_PROCESS_MEMORY_ROUTINE64 = HANDLE, DWORD64, Void*, DWORD, DWORD* -> BOOL
alias PFUNCTION_TABLE_ACCESS_ROUTINE64 = HANDLE, DWORD64 -> Void*
Expand Down
134 changes: 86 additions & 48 deletions src/lib_c/x86_64-windows-msvc/c/winnt.cr
Original file line number Diff line number Diff line change
Expand Up @@ -140,54 +140,84 @@ lib LibC
JOB_OBJECT_MSG_EXIT_PROCESS = 7
JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS = 8

struct CONTEXT
p1Home : DWORD64
p2Home : DWORD64
p3Home : DWORD64
p4Home : DWORD64
p5Home : DWORD64
p6Home : DWORD64
contextFlags : DWORD
mxCsr : DWORD
segCs : WORD
segDs : WORD
segEs : WORD
segFs : WORD
segGs : WORD
segSs : WORD
eFlags : DWORD
dr0 : DWORD64
dr1 : DWORD64
dr2 : DWORD64
dr3 : DWORD64
dr6 : DWORD64
dr7 : DWORD64
rax : DWORD64
rcx : DWORD64
rdx : DWORD64
rbx : DWORD64
rsp : DWORD64
rbp : DWORD64
rsi : DWORD64
rdi : DWORD64
r8 : DWORD64
r9 : DWORD64
r10 : DWORD64
r11 : DWORD64
r12 : DWORD64
r13 : DWORD64
r14 : DWORD64
r15 : DWORD64
rip : DWORD64
fltSave : UInt8[512] # DUMMYUNIONNAME
vectorRegister : UInt8[16][26] # M128A[26]
vectorControl : DWORD64
debugControl : DWORD64
lastBranchToRip : DWORD64
lastBranchFromRip : DWORD64
lastExceptionToRip : DWORD64
lastExceptionFromRip : DWORD64
end
{% if flag?(:x86_64) %}
struct CONTEXT
p1Home : DWORD64
p2Home : DWORD64
p3Home : DWORD64
p4Home : DWORD64
p5Home : DWORD64
p6Home : DWORD64
contextFlags : DWORD
mxCsr : DWORD
segCs : WORD
segDs : WORD
segEs : WORD
segFs : WORD
segGs : WORD
segSs : WORD
eFlags : DWORD
dr0 : DWORD64
dr1 : DWORD64
dr2 : DWORD64
dr3 : DWORD64
dr6 : DWORD64
dr7 : DWORD64
rax : DWORD64
rcx : DWORD64
rdx : DWORD64
rbx : DWORD64
rsp : DWORD64
rbp : DWORD64
rsi : DWORD64
rdi : DWORD64
r8 : DWORD64
r9 : DWORD64
r10 : DWORD64
r11 : DWORD64
r12 : DWORD64
r13 : DWORD64
r14 : DWORD64
r15 : DWORD64
rip : DWORD64
fltSave : UInt8[512] # DUMMYUNIONNAME
vectorRegister : UInt8[16][26] # M128A[26]
vectorControl : DWORD64
debugControl : DWORD64
lastBranchToRip : DWORD64
lastBranchFromRip : DWORD64
lastExceptionToRip : DWORD64
lastExceptionFromRip : DWORD64
end
{% elsif flag?(:aarch64) %}
struct ARM64_NT_NEON128_DUMMYSTRUCTNAME
low : ULongLong
high : LongLong
end

union ARM64_NT_NEON128
dummystructname : ARM64_NT_NEON128_DUMMYSTRUCTNAME
d : Double[2]
s : Float[4]
h : WORD[8]
b : BYTE[16]
end

struct CONTEXT
contextFlags : DWORD
cpsr : DWORD
x : DWORD64[31] # x29 = fp, x30 = lr
sp : DWORD64
pc : DWORD64
v : ARM64_NT_NEON128[32]
fpcr : DWORD
fpsr : DWORD
bcr : DWORD[8]
bvr : DWORD64[8]
wcr : DWORD[8]
wvr : DWORD64[8]
end
{% end %}

{% if flag?(:x86_64) %}
CONTEXT_AMD64 = DWORD.new!(0x00100000)
Expand All @@ -211,6 +241,14 @@ lib LibC
CONTEXT_EXTENDED_REGISTERS = CONTEXT_i386 | 0x00000020

CONTEXT_FULL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS
{% elsif flag?(:aarch64) %}
CONTEXT_ARM64 = DWORD.new!(0x00400000)

CONTEXT_ARM64_CONTROL = CONTEXT_ARM64 | 0x1
CONTEXT_ARM64_INTEGER = CONTEXT_ARM64 | 0x2
CONTEXT_ARM64_FLOATING_POINT = CONTEXT_ARM64 | 0x4

CONTEXT_FULL = CONTEXT_ARM64_CONTROL | CONTEXT_ARM64_INTEGER | CONTEXT_ARM64_FLOATING_POINT
{% end %}

fun RtlCaptureContext(contextRecord : CONTEXT*)
Expand Down