2010-11-09 37 views
14

Chúng tôi có một ứng dụng C++ với một JVM được nhúng (Sun's). Bởi vì chúng tôi đăng ký các trình xử lý tín hiệu của riêng mình, chúng tôi khuyên bạn nên làm như vậy trước khi khởi tạo JVM vì nó cài đặt các trình xử lý riêng của mình (see here).Chùm tín hiệu JVM SIGPIPE

Từ những gì tôi hiểu, JVM biết nội bộ nếu tín hiệu có nguồn gốc từ mã riêng của nó và nếu nó không truyền nó dọc theo chuỗi - đến bộ xử lý của chúng tôi.

Những gì chúng ta bắt đầu nhìn thấy là chúng ta đang nhận được SIGPIPEs, với một chồng gọi đó trông gần như thế này (mục trên cùng là xử lý tín hiệu của chúng tôi):

/.../libos_independent_utilities.so(_ZN2os32smart_synchronous_signal_handlerEiP7siginfoPv+0x9) [0x2b124f7a3989] 
/.../jvm/jre/lib/amd64/server/libjvm.so [0x2aaaab05dc6c] 
/.../jvm/jre/lib/amd64/server/libjvm.so [0x2aaaab05bffb] 
/.../jvm/jre/lib/amd64/server/libjvm.so(JVM_handle_linux_signal+0x718) [0x2aaaab05e878] 
/.../jvm/jre/lib/amd64/server/libjvm.so [0x2aaaab05bf0e] 
/lib64/libpthread.so.0 [0x3c2140e4c0] 
/lib64/libpthread.so.0(send+0x91) [0x3c2140d841] 
/.../jvm/jre/lib/amd64/libnet.so [0x2aaabd360269] 
/.../jvm/jre/lib/amd64/libnet.so(Java_java_net_SocketOutputStream_socketWrite0+0xee) [0x2aaabd35cf4e] 
[0x2aaaaeb3bf7f] 

Nó có vẻ như JVM là quyết định mà SIGPIPE được nâng lên từ send nên được chuyển đến bộ xử lý tín hiệu của chúng tôi. Có đúng khi làm như vậy không?

Ngoài ra, tại sao ngăn xếp cuộc gọi không đầy đủ? Tôi có nghĩa là rõ ràng nó không thể hiển thị cho tôi mã java trước socketWrite0 nhưng tại sao tôi không thể nhìn thấy ngăn xếp trước mã java?

+0

Bạn đã cài đặt bộ xử lý tín hiệu cho SIGPIPE chưa? (nếu có, có - thông thường bạn sẽ nhận được SIGPIPE từ các cuộc gọi send() khi ai đó ghi vào một ổ cắm bị hỏng) – nos

+0

Tôi biết rằng 'send' có thể tăng SIGPIPE. Tôi chỉ đơn thuần đặt câu hỏi về quyết định của JVM để chuyển chúng cho tôi, tại sao nó không đưa ra một ngoại lệ? –

+0

Nhưng bạn đã không cài đặt một trình xử lý cho nó? – nos

Trả lời

7

JVM không thể biết SIGPIPE đến từ mã riêng của nó hay mã của bạn. Thông tin đó không được đưa ra bởi tín hiệu. Bởi vì nó không muốn bạn bỏ lỡ bất kỳ sự kiện có thể nào mà bạn có thể quan tâm, nó phải truyền cho bạn tất cả SIGPIPE, ngay cả những cái mà nó hóa ra là từ mã riêng của nó.

Tín hiệu Unix có hai hương vị - "đồng bộ" và "không đồng bộ". Một vài điều kiện đặc biệt khi thực thi mã có thể gây ra bẫy và dẫn đến tín hiệu "đồng bộ". Đây là những thứ như truy cập bộ nhớ không được ký hiệu (SIGBUS), truy cập bộ nhớ bất hợp pháp, thường là NULL, (SIGSEGV), chia cho số không và các lỗi toán học khác (SIGFPE), hướng dẫn không thể giải mã (SIGILL), v.v. Chúng có ngữ cảnh thực thi chính xác và được gửi trực tiếp đến luồng gây ra chúng. Trình xử lý tín hiệu có thể tra cứu ngăn xếp và xem "này tôi có quyền truy cập bộ nhớ bất hợp pháp đang thực thi mã java và con trỏ là NULL. Hãy để tôi sửa lỗi đó."

Ngược lại, các tín hiệu tương tác với thế giới bên ngoài là sự đa dạng "không đồng bộ" và bao gồm những thứ như SIGTERM, SIGQUIT, SIGUSR1, v.v. Những ngữ cảnh này không có ngữ cảnh thực hiện cố định. Đối với các chương trình luồng, chúng được phân phối khá ngẫu nhiên vào bất kỳ luồng nào. Quan trọng hơn, SIGPIPE nằm trong số này. Có, trong một số ý nghĩa, nó thường được kết hợp với một cuộc gọi hệ thống. Nhưng nó là khá có thể (ví dụ) có hai chủ đề nghe hai kết nối riêng biệt, cả hai đều đóng trước khi một trong hai luồng được lên lịch. Hạt nhân chỉ đảm bảo rằng có một SIGPIPE đang chờ xử lý (việc thực hiện thông thường là một bitmask của các tín hiệu đang chờ xử lý), và giao dịch với nó để lên lịch lại bất kỳ luồng nào trong tiến trình. Đây chỉ là một trong những trường hợp đơn giản nhất có thể khi JVM có thể không có đủ thông tin để loại trừ mã máy khách của bạn đang quan tâm đến tín hiệu này.

(Đối với những gì xảy ra với cuộc gọi đã đọc, họ trả về "đã xảy ra lỗi: EINTR" và tiếp tục. Tại thời điểm này, JVM có thể biến điều đó thành ngoại lệ, nhưng trở lại xảy ra sau tín hiệu giao hàng và xử lý tín hiệu kích hoạt.)

Kết quả là bạn sẽ chỉ phải đối phó với các kết quả dương tính giả. (Và đối phó với việc chỉ nhận được một tín hiệu mà hai có thể đã được mong đợi.)

+0

thì làm cách nào để biết liệu tất cả các tín hiệu khác có được đăng ký đến từ mã của nó không? –

+0

Tôi có bộ xử lý tín hiệu cho hầu hết mọi tín hiệu, đây là lần đầu tiên hiển thị hành vi có vẻ xấu. Ngoài ra, JVM được đăng ký để xử lý SIGPIPE, một bằng chứng về điều đó là 'JVM_handle_linux_signal' trong callstack - tài liệu này cũng nói rằng JVM bắt SIGPIPE http://www.oracle.com/technetwork/java/javase/signals- 139944.html # gbzbl Có nhiều tình huống phức tạp hơn khi JVM chỉ đơn giản là "biết" nếu một tín hiệu đến từ mã riêng của nó, ví dụ tối ưu hóa con trỏ null, vì vậy tôi vẫn không hiểu đối số của bạn. –

+0

Cảm ơn, lời giải thích của bạn có ý nghĩa và ít nhiều là cách tôi tưởng tượng JVM đưa ra quyết định có nên chuỗi tín hiệu hay không. Tuy nhiên, nếu bạn nhìn vào ngăn xếp cuộc gọi mà tôi có trong trình xử lý tín hiệu của tôi, thì JVM có thể kiểm tra ngăn xếp và nhận ra rằng SIGPIPE có nguồn gốc từ mã riêng của nó, ví dụ bằng cách nhìn thấy địa chỉ 'Java_java_net_SocketOutputStream_socketWrite0' trong ngăn xếp cuộc gọi . –

Các vấn đề liên quan