From patchwork Tue Jun 22 08:36:53 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnaud Charlet X-Patchwork-Id: 56412 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id B53A6B6EDD for ; Tue, 22 Jun 2010 18:37:14 +1000 (EST) Received: (qmail 24401 invoked by alias); 22 Jun 2010 08:37:00 -0000 Received: (qmail 24286 invoked by uid 22791); 22 Jun 2010 08:36:57 -0000 X-SWARE-Spam-Status: No, hits=-0.9 required=5.0 tests=AWL, BAYES_40, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mel.act-europe.fr (HELO mel.act-europe.fr) (212.99.106.210) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 22 Jun 2010 08:36:52 +0000 Received: from localhost (localhost [127.0.0.1]) by filtered-smtp.eu.adacore.com (Postfix) with ESMTP id 7E581CB025E; Tue, 22 Jun 2010 10:36:53 +0200 (CEST) Received: from mel.act-europe.fr ([127.0.0.1]) by localhost (smtp.eu.adacore.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id QvtNpjlXiCOb; Tue, 22 Jun 2010 10:36:53 +0200 (CEST) Received: from saumur.act-europe.fr (saumur.act-europe.fr [10.10.0.183]) by mel.act-europe.fr (Postfix) with ESMTP id 660D2CB022F; Tue, 22 Jun 2010 10:36:53 +0200 (CEST) Received: by saumur.act-europe.fr (Postfix, from userid 525) id 5EA4FD9B31; Tue, 22 Jun 2010 10:36:53 +0200 (CEST) Date: Tue, 22 Jun 2010 10:36:53 +0200 From: Arnaud Charlet To: gcc-patches@gcc.gnu.org Cc: Pascal Obry Subject: [Ada] Fix implementation of the vectored sockets on Windows Message-ID: <20100622083653.GA28900@adacore.com> Mime-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.9i X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Fix a race condition in the way the vectored sockets emulation was implemented on Windows. Also fix the way the vectors are filled. Tested on i686-pc-mingw32, committed on trunk 2010-06-22 Pascal Obry * g-socthi-mingw.adb: Fix implementation of the vectored sockets on Windows. (C_Recvmsg): Make sure the routine is atomic. Also fully fill vectors in the proper order. (C_Sendmsg): Make sure the routine is atomic. Index: g-socthi-mingw.adb =================================================================== --- g-socthi-mingw.adb (revision 161073) +++ g-socthi-mingw.adb (working copy) @@ -6,7 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 2001-2009, AdaCore -- +-- Copyright (C) 2001-2010, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -37,8 +37,13 @@ -- This version is for NT -with Interfaces.C.Strings; use Interfaces.C.Strings; -with System; use System; +with Ada.Streams; use Ada.Streams; +with Ada.Unchecked_Conversion; +with Interfaces.C.Strings; use Interfaces.C.Strings; +with System; use System; +with System.Storage_Elements; use System.Storage_Elements; + +with GNAT.Task_Lock; package body GNAT.Sockets.Thin is @@ -273,8 +278,10 @@ package body GNAT.Sockets.Thin is is use type C.size_t; - Res : C.int; - Count : C.int := 0; + Res : C.int; + Count : C.int := 0; + Locked : Boolean := False; + -- Set to false when the lock is activated MH : Msghdr; for MH'Address use Msg; @@ -283,26 +290,105 @@ package body GNAT.Sockets.Thin is for Iovec'Address use MH.Msg_Iov; pragma Import (Ada, Iovec); + Iov_Index : Integer; + Current_Iovec : Vector_Element; + + function To_Access is new Ada.Unchecked_Conversion + (System.Address, Stream_Element_Reference); + pragma Warnings (Off, Stream_Element_Reference); + + Req : Request_Type (Name => N_Bytes_To_Read); + begin -- Windows does not provide an implementation of recvmsg(). The spec for -- WSARecvMsg() is incompatible with the data types we define, and is -- not available in all versions of Windows. So, we use C_Recv instead. - for J in Iovec'Range loop + -- First, wait for some data to be available if socket is blocking + + declare + Selector : Selector_Type; + R_Socket_Set : Socket_Set_Type; + W_Socket_Set : Socket_Set_Type; + Status : Selector_Status; + Req : Request_Type (Name => Non_Blocking_IO); + begin + Control_Socket (Socket_Type (S), Req); + + if not Req.Enabled then + -- We are in a blocking IO mode + Create_Selector (Selector); + + Set (R_Socket_Set, Socket_Type (S)); + + Check_Selector (Selector, R_Socket_Set, W_Socket_Set, Status); + + Close_Selector (Selector); + end if; + end; + + GNAT.Task_Lock.Lock; + Locked := True; + + -- Check how much data are available + + Control_Socket (Socket_Type (S), Req); + + -- Fill the vectors + + Iov_Index := -1; + Current_Iovec := (Base => null, Length => 0); + + loop + if Current_Iovec.Length = 0 then + Iov_Index := Iov_Index + 1; + exit when Iov_Index > Integer (Iovec'Last); + Current_Iovec := Iovec (SOSC.Msg_Iovlen_T (Iov_Index)); + end if; + Res := C_Recv (S, - Iovec (J).Base.all'Address, - C.int (Iovec (J).Length), + Current_Iovec.Base.all'Address, + C.int (Current_Iovec.Length), Flags); if Res < 0 then + Task_Lock.Unlock; return System.CRTL.ssize_t (Res); + + elsif Res = 0 then + exit; + else + pragma Assert (Stream_Element_Count (Res) <= Current_Iovec.Length); + Count := Count + Res; + Current_Iovec.Length := + Current_Iovec.Length - Stream_Element_Count (Res); + Current_Iovec.Base := + To_Access (Current_Iovec.Base.all'Address + + Storage_Offset (Res)); + + -- If we have read all the data that was initially available, + -- do not attempt to receive more, since this might block, or + -- merge data from successive datagrams in case of a datagram- + -- oriented socket. + + exit when Natural (Count) >= Req.Size; end if; end loop; + + Task_Lock.Unlock; + return System.CRTL.ssize_t (Count); + + exception + when others => + if Locked then + Task_Lock.Unlock; + end if; + raise; end C_Recvmsg; -------------- @@ -428,7 +514,10 @@ package body GNAT.Sockets.Thin is -- not available in all versions of Windows. So, we'll use C_Sendto -- instead. + Task_Lock.Lock; + for J in Iovec'Range loop + Res := C_Sendto (S, @@ -439,13 +528,20 @@ package body GNAT.Sockets.Thin is Tolen => C.int (MH.Msg_Namelen)); if Res < 0 then + Task_Lock.Unlock; return System.CRTL.ssize_t (Res); else Count := Count + Res; end if; end loop; + Task_Lock.Unlock; + return System.CRTL.ssize_t (Count); + exception + when others => + Task_Lock.Unlock; + raise; end C_Sendmsg; --------------