@@ -55,6 +55,8 @@ DARSHAN_FORWARD_DECL(creat64, int, (const char* path, mode_t mode));
55
55
DARSHAN_FORWARD_DECL (dup , int , (int oldfd ));
56
56
DARSHAN_FORWARD_DECL (dup2 , int , (int oldfd , int newfd ));
57
57
DARSHAN_FORWARD_DECL (dup3 , int , (int oldfd , int newfd , int flags ));
58
+ DARSHAN_FORWARD_DECL (fcntl , int , (int , int , ...));
59
+ DARSHAN_FORWARD_DECL (fcntl64 , int , (int , int , ...));
58
60
DARSHAN_FORWARD_DECL (fileno , int , (FILE * stream ));
59
61
DARSHAN_FORWARD_DECL (mkstemp , int , (char * template ));
60
62
DARSHAN_FORWARD_DECL (mkostemp , int , (char * template , int flags ));
@@ -787,6 +789,85 @@ int DARSHAN_DECL(dup3)(int oldfd, int newfd, int flags)
787
789
return (ret );
788
790
}
789
791
792
+ /* wrapping fcntl is a little strange for two related reasons:
793
+ * - the code can do a lot of different things based on 'cmd'
794
+ * - some of those 'cmd' (not all) take a third argument
795
+ *
796
+ * There are some worrying notes in the documentation about calling va_args
797
+ * when there's no third (variable) argument, but we observed glibc doing that
798
+ * and our testing seems to indicate it's ok to do so.
799
+ *
800
+ * So we'll always grab the variable argument, even if it's not there, and
801
+ * always pass whatever we get to the real fcntl. Then we'll figure out if the
802
+ * command was something we should log or not, and update our stats accordingly
803
+ */
804
+
805
+ int DARSHAN_DECL (fcntl )(int fd , int cmd , ...)
806
+ {
807
+ int ret ;
808
+ double tm1 , tm2 ;
809
+ va_list arg ;
810
+ void * next ;
811
+
812
+ MAP_OR_FAIL (fcntl );
813
+
814
+ va_start (arg , cmd );
815
+ next = va_arg (arg , void * );
816
+ va_end (arg );
817
+
818
+ tm1 = POSIX_WTIME ();
819
+ ret = __real_fcntl (fd , cmd , next );
820
+ tm2 = POSIX_WTIME ();
821
+
822
+ struct posix_file_record_ref * rec_ref ;
823
+
824
+ /* some code (e.g. python) prefers (portabilty? functionality?) to
825
+ * duplicate the file descriptor via fcntl instead of dup/dup2/dup3 */
826
+ if (ret >= 0 && (cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC )) {
827
+ POSIX_PRE_RECORD ();
828
+ rec_ref = darshan_lookup_record_ref (posix_runtime -> fd_hash ,
829
+ & fd , sizeof (fd ));
830
+
831
+ POSIX_RECORD_REFOPEN (ret , rec_ref , tm1 , tm2 , POSIX_DUPS );
832
+ POSIX_POST_RECORD ();
833
+ }
834
+
835
+ return ret ;
836
+ }
837
+
838
+ int DARSHAN_DECL (fcntl64 )(int fd , int cmd , ...)
839
+ {
840
+ int ret ;
841
+ double tm1 , tm2 ;
842
+ va_list arg ;
843
+ void * next ;
844
+
845
+ MAP_OR_FAIL (fcntl64 );
846
+
847
+ va_start (arg , cmd );
848
+ next = va_arg (arg , void * );
849
+ va_end (arg );
850
+
851
+ tm1 = POSIX_WTIME ();
852
+ ret = __real_fcntl64 (fd , cmd , next );
853
+ tm2 = POSIX_WTIME ();
854
+
855
+ struct posix_file_record_ref * rec_ref ;
856
+
857
+ /* this is a duplicate of code in fcntl, but when I try to break this out
858
+ * into a separate 'fcntl_common' routine, POSIX_PRE_RECORD() macro cannot
859
+ * find the __darshan_disabled variable, and furthermore I get weird
860
+ * "failed to seek" errors. Am I going to have to make this a macro? */
861
+ if (ret >= 0 && (cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC )) {
862
+ POSIX_PRE_RECORD ();
863
+ rec_ref = darshan_lookup_record_ref (posix_runtime -> fd_hash ,
864
+ & fd , sizeof (fd ));
865
+ POSIX_RECORD_REFOPEN (ret , rec_ref , tm1 , tm2 , POSIX_DUPS );
866
+ POSIX_POST_RECORD ();
867
+ }
868
+
869
+ return ret ;
870
+ }
790
871
int DARSHAN_DECL (fileno )(FILE * stream )
791
872
{
792
873
int ret ;
0 commit comments