@@ -155,7 +155,6 @@ use cfg_if::cfg_if;
155155use crate :: { Error , Result } ;
156156use crate :: errno:: Errno ;
157157use libc:: { self , c_int, tcflag_t} ;
158- use std:: cell:: { Ref , RefCell } ;
159158use std:: convert:: { From , TryFrom } ;
160159use std:: mem;
161160use std:: os:: unix:: io:: RawFd ;
@@ -167,9 +166,20 @@ use crate::unistd::Pid;
167166/// This is a wrapper around the `libc::termios` struct that provides a safe interface for the
168167/// standard fields. The only safe way to obtain an instance of this struct is to extract it from
169168/// an open port using `tcgetattr()`.
170- #[ derive( Clone , Debug , Eq , PartialEq ) ]
169+ #[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
171170pub struct Termios {
172- inner : RefCell < libc:: termios > ,
171+ // The actual fields present in `libc::termios`, their types, and even their interpretations
172+ // vary from one platform to another. We want to expose a portable subset as public fields of
173+ // `Termios`, using stable types, and allow access to the rest via accessors, if at all.
174+ //
175+ // So we carry around this private `libc::termios`, initialize our public fields from it
176+ // whenever it's changed (see `set_libc_termios`), and propagate our public fields' values back
177+ // into it whenever we need a real `libc::termios` to pass to `tcsetattr`, `cfmakeraw`, or the
178+ // like (see `get_libc_termios`).
179+ //
180+ // Any fields unknown to us get reasonable values from the initial `tcgetattr` used to create
181+ // this `Termios`, and are thus passed through to subsequent `tcsetattr` calls unchanged.
182+ inner : libc:: termios ,
173183 /// Input mode flags (see `termios.c_iflag` documentation)
174184 pub input_flags : InputFlags ,
175185 /// Output mode flags (see `termios.c_oflag` documentation)
@@ -183,43 +193,24 @@ pub struct Termios {
183193}
184194
185195impl Termios {
186- /// Exposes an immutable reference to the underlying `libc::termios` data structure.
196+ /// Return a copy of the internal `libc::termios` structure.
187197 ///
188198 /// This is not part of `nix`'s public API because it requires additional work to maintain type
189199 /// safety.
190- pub ( crate ) fn get_libc_termios ( & self ) -> Ref < libc:: termios > {
191- {
192- let mut termios = self . inner . borrow_mut ( ) ;
193- termios. c_iflag = self . input_flags . bits ( ) ;
194- termios. c_oflag = self . output_flags . bits ( ) ;
195- termios. c_cflag = self . control_flags . bits ( ) ;
196- termios. c_lflag = self . local_flags . bits ( ) ;
197- termios. c_cc = self . control_chars ;
198- }
199- self . inner . borrow ( )
200- }
201-
202- /// Exposes the inner `libc::termios` datastore within `Termios`.
203- ///
204- /// This is unsafe because if this is used to modify the inner `libc::termios` struct, it will
205- /// not automatically update the safe wrapper type around it. In this case it should also be
206- /// paired with a call to `update_wrapper()` so that the wrapper-type and internal
207- /// representation stay consistent.
208- pub ( crate ) unsafe fn get_libc_termios_mut ( & mut self ) -> * mut libc:: termios {
209- {
210- let mut termios = self . inner . borrow_mut ( ) ;
211- termios. c_iflag = self . input_flags . bits ( ) ;
212- termios. c_oflag = self . output_flags . bits ( ) ;
213- termios. c_cflag = self . control_flags . bits ( ) ;
214- termios. c_lflag = self . local_flags . bits ( ) ;
215- termios. c_cc = self . control_chars ;
216- }
217- self . inner . as_ptr ( )
200+ pub ( crate ) fn get_libc_termios ( & self ) -> libc:: termios {
201+ let mut termios = self . inner ;
202+ termios. c_iflag = self . input_flags . bits ( ) ;
203+ termios. c_oflag = self . output_flags . bits ( ) ;
204+ termios. c_cflag = self . control_flags . bits ( ) ;
205+ termios. c_lflag = self . local_flags . bits ( ) ;
206+ termios. c_cc = self . control_chars ;
207+ termios
218208 }
219209
220- /// Updates the wrapper values from the internal `libc::termios` data structure.
221- pub ( crate ) fn update_wrapper ( & mut self ) {
222- let termios = * self . inner . borrow_mut ( ) ;
210+ /// Set the internal `libc::termios` structure to `termios`,
211+ /// and update the public fields.
212+ pub ( crate ) fn set_libc_termios ( & mut self , termios : & libc:: termios ) {
213+ self . inner = * termios;
223214 self . input_flags = InputFlags :: from_bits_truncate ( termios. c_iflag ) ;
224215 self . output_flags = OutputFlags :: from_bits_truncate ( termios. c_oflag ) ;
225216 self . control_flags = ControlFlags :: from_bits_truncate ( termios. c_cflag ) ;
@@ -231,7 +222,7 @@ impl Termios {
231222impl From < libc:: termios > for Termios {
232223 fn from ( termios : libc:: termios ) -> Self {
233224 Termios {
234- inner : RefCell :: new ( termios) ,
225+ inner : termios,
235226 input_flags : InputFlags :: from_bits_truncate ( termios. c_iflag ) ,
236227 output_flags : OutputFlags :: from_bits_truncate ( termios. c_oflag ) ,
237228 control_flags : ControlFlags :: from_bits_truncate ( termios. c_cflag ) ,
@@ -243,7 +234,7 @@ impl From<libc::termios> for Termios {
243234
244235impl From < Termios > for libc:: termios {
245236 fn from ( termios : Termios ) -> Self {
246- termios. inner . into_inner ( )
237+ termios. inner
247238 }
248239}
249240
@@ -881,7 +872,7 @@ cfg_if!{
881872 /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
882873 pub fn cfgetispeed( termios: & Termios ) -> u32 {
883874 let inner_termios = termios. get_libc_termios( ) ;
884- unsafe { libc:: cfgetispeed( & * inner_termios) as u32 }
875+ unsafe { libc:: cfgetispeed( & inner_termios) as u32 }
885876 }
886877
887878 /// Get output baud rate (see
@@ -890,17 +881,17 @@ cfg_if!{
890881 /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
891882 pub fn cfgetospeed( termios: & Termios ) -> u32 {
892883 let inner_termios = termios. get_libc_termios( ) ;
893- unsafe { libc:: cfgetospeed( & * inner_termios) as u32 }
884+ unsafe { libc:: cfgetospeed( & inner_termios) as u32 }
894885 }
895886
896887 /// Set input baud rate (see
897888 /// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
898889 ///
899890 /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
900891 pub fn cfsetispeed<T : Into <u32 >>( termios: & mut Termios , baud: T ) -> Result <( ) > {
901- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
902- let res = unsafe { libc:: cfsetispeed( inner_termios, baud. into( ) as libc:: speed_t) } ;
903- termios. update_wrapper ( ) ;
892+ let mut inner_termios = termios. get_libc_termios ( ) ;
893+ let res = unsafe { libc:: cfsetispeed( & mut inner_termios as * mut _ , baud. into( ) as libc:: speed_t) } ;
894+ termios. set_libc_termios ( & inner_termios ) ;
904895 Errno :: result( res) . map( drop)
905896 }
906897
@@ -909,9 +900,9 @@ cfg_if!{
909900 ///
910901 /// `cfsetospeed()` sets the output baud rate in the given termios structure.
911902 pub fn cfsetospeed<T : Into <u32 >>( termios: & mut Termios , baud: T ) -> Result <( ) > {
912- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
913- let res = unsafe { libc:: cfsetospeed( inner_termios, baud. into( ) as libc:: speed_t) } ;
914- termios. update_wrapper ( ) ;
903+ let mut inner_termios = termios. get_libc_termios ( ) ;
904+ let res = unsafe { libc:: cfsetospeed( & mut inner_termios as * mut _ , baud. into( ) as libc:: speed_t) } ;
905+ termios. set_libc_termios ( & inner_termios ) ;
915906 Errno :: result( res) . map( drop)
916907 }
917908
@@ -921,9 +912,9 @@ cfg_if!{
921912 /// `cfsetspeed()` sets the input and output baud rate in the given termios structure. Note that
922913 /// this is part of the 4.4BSD standard and not part of POSIX.
923914 pub fn cfsetspeed<T : Into <u32 >>( termios: & mut Termios , baud: T ) -> Result <( ) > {
924- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
925- let res = unsafe { libc:: cfsetspeed( inner_termios, baud. into( ) as libc:: speed_t) } ;
926- termios. update_wrapper ( ) ;
915+ let mut inner_termios = termios. get_libc_termios ( ) ;
916+ let res = unsafe { libc:: cfsetspeed( & mut inner_termios as * mut _ , baud. into( ) as libc:: speed_t) } ;
917+ termios. set_libc_termios ( & inner_termios ) ;
927918 Errno :: result( res) . map( drop)
928919 }
929920 } else {
@@ -935,7 +926,7 @@ cfg_if!{
935926 /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
936927 pub fn cfgetispeed( termios: & Termios ) -> BaudRate {
937928 let inner_termios = termios. get_libc_termios( ) ;
938- unsafe { libc:: cfgetispeed( & * inner_termios) } . try_into( ) . unwrap( )
929+ unsafe { libc:: cfgetispeed( & inner_termios) } . try_into( ) . unwrap( )
939930 }
940931
941932 /// Get output baud rate (see
@@ -944,17 +935,17 @@ cfg_if!{
944935 /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
945936 pub fn cfgetospeed( termios: & Termios ) -> BaudRate {
946937 let inner_termios = termios. get_libc_termios( ) ;
947- unsafe { libc:: cfgetospeed( & * inner_termios) } . try_into( ) . unwrap( )
938+ unsafe { libc:: cfgetospeed( & inner_termios) } . try_into( ) . unwrap( )
948939 }
949940
950941 /// Set input baud rate (see
951942 /// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
952943 ///
953944 /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
954945 pub fn cfsetispeed( termios: & mut Termios , baud: BaudRate ) -> Result <( ) > {
955- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
956- let res = unsafe { libc:: cfsetispeed( inner_termios, baud as libc:: speed_t) } ;
957- termios. update_wrapper ( ) ;
946+ let mut inner_termios = termios. get_libc_termios ( ) ;
947+ let res = unsafe { libc:: cfsetispeed( & mut inner_termios as * mut _ , baud as libc:: speed_t) } ;
948+ termios. set_libc_termios ( & inner_termios ) ;
958949 Errno :: result( res) . map( drop)
959950 }
960951
@@ -963,9 +954,9 @@ cfg_if!{
963954 ///
964955 /// `cfsetospeed()` sets the output baud rate in the given `Termios` structure.
965956 pub fn cfsetospeed( termios: & mut Termios , baud: BaudRate ) -> Result <( ) > {
966- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
967- let res = unsafe { libc:: cfsetospeed( inner_termios, baud as libc:: speed_t) } ;
968- termios. update_wrapper ( ) ;
957+ let mut inner_termios = termios. get_libc_termios ( ) ;
958+ let res = unsafe { libc:: cfsetospeed( & mut inner_termios as * mut _ , baud as libc:: speed_t) } ;
959+ termios. set_libc_termios ( & inner_termios ) ;
969960 Errno :: result( res) . map( drop)
970961 }
971962
@@ -975,9 +966,9 @@ cfg_if!{
975966 /// `cfsetspeed()` sets the input and output baud rate in the given `Termios` structure. Note that
976967 /// this is part of the 4.4BSD standard and not part of POSIX.
977968 pub fn cfsetspeed( termios: & mut Termios , baud: BaudRate ) -> Result <( ) > {
978- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
979- let res = unsafe { libc:: cfsetspeed( inner_termios, baud as libc:: speed_t) } ;
980- termios. update_wrapper ( ) ;
969+ let mut inner_termios = termios. get_libc_termios ( ) ;
970+ let res = unsafe { libc:: cfsetspeed( & mut inner_termios as * mut _ , baud as libc:: speed_t) } ;
971+ termios. set_libc_termios ( & inner_termios ) ;
981972 Errno :: result( res) . map( drop)
982973 }
983974 }
@@ -990,11 +981,11 @@ cfg_if!{
990981/// character, echoing is disabled, and all special input and output processing is disabled. Note
991982/// that this is a non-standard function, but is available on Linux and BSDs.
992983pub fn cfmakeraw ( termios : & mut Termios ) {
993- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
984+ let mut inner_termios = termios. get_libc_termios ( ) ;
994985 unsafe {
995- libc:: cfmakeraw ( inner_termios) ;
986+ libc:: cfmakeraw ( & mut inner_termios as * mut _ ) ;
996987 }
997- termios. update_wrapper ( ) ;
988+ termios. set_libc_termios ( & inner_termios ) ;
998989}
999990
1000991/// Configures the port to "sane" mode (like the configuration of a newly created terminal) (see
@@ -1003,11 +994,11 @@ pub fn cfmakeraw(termios: &mut Termios) {
1003994/// Note that this is a non-standard function, available on FreeBSD.
1004995#[ cfg( target_os = "freebsd" ) ]
1005996pub fn cfmakesane ( termios : & mut Termios ) {
1006- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
997+ let mut inner_termios = termios. get_libc_termios ( ) ;
1007998 unsafe {
1008- libc:: cfmakesane ( inner_termios) ;
999+ libc:: cfmakesane ( & mut inner_termios as * mut _ ) ;
10091000 }
1010- termios. update_wrapper ( ) ;
1001+ termios. set_libc_termios ( & inner_termios ) ;
10111002}
10121003
10131004/// Return the configuration of a port
@@ -1034,7 +1025,7 @@ pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
10341025/// *any* of the parameters were successfully set, not only if all were set successfully.
10351026pub fn tcsetattr ( fd : RawFd , actions : SetArg , termios : & Termios ) -> Result < ( ) > {
10361027 let inner_termios = termios. get_libc_termios ( ) ;
1037- Errno :: result ( unsafe { libc:: tcsetattr ( fd, actions as c_int , & * inner_termios) } ) . map ( drop)
1028+ Errno :: result ( unsafe { libc:: tcsetattr ( fd, actions as c_int , & inner_termios) } ) . map ( drop)
10381029}
10391030
10401031/// Block until all output data is written (see
0 commit comments