450 return |
449 return |
451 } |
450 } |
452 |
451 |
453 //sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.__xnet_recvmsg |
452 //sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.__xnet_recvmsg |
454 |
453 |
455 func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) { |
454 func recvmsgRaw(fd int, iov []Iovec, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) { |
456 var msg Msghdr |
455 var msg Msghdr |
457 var rsa RawSockaddrAny |
456 msg.Name = (*byte)(unsafe.Pointer(rsa)) |
458 msg.Name = (*byte)(unsafe.Pointer(&rsa)) |
|
459 msg.Namelen = uint32(SizeofSockaddrAny) |
457 msg.Namelen = uint32(SizeofSockaddrAny) |
460 var iov Iovec |
458 var dummy byte |
461 if len(p) > 0 { |
|
462 iov.Base = (*int8)(unsafe.Pointer(&p[0])) |
|
463 iov.SetLen(len(p)) |
|
464 } |
|
465 var dummy int8 |
|
466 if len(oob) > 0 { |
459 if len(oob) > 0 { |
467 // receive at least one normal byte |
460 // receive at least one normal byte |
468 if len(p) == 0 { |
461 if emptyIovecs(iov) { |
469 iov.Base = &dummy |
462 var iova [1]Iovec |
470 iov.SetLen(1) |
463 iova[0].Base = &dummy |
|
464 iova[0].SetLen(1) |
|
465 iov = iova[:] |
471 } |
466 } |
472 msg.Accrightslen = int32(len(oob)) |
467 msg.Accrightslen = int32(len(oob)) |
473 } |
468 } |
474 msg.Iov = &iov |
469 if len(iov) > 0 { |
475 msg.Iovlen = 1 |
470 msg.Iov = &iov[0] |
|
471 msg.SetIovlen(len(iov)) |
|
472 } |
476 if n, err = recvmsg(fd, &msg, flags); n == -1 { |
473 if n, err = recvmsg(fd, &msg, flags); n == -1 { |
477 return |
474 return |
478 } |
475 } |
479 oobn = int(msg.Accrightslen) |
476 oobn = int(msg.Accrightslen) |
480 // source address is only specified if the socket is unconnected |
|
481 if rsa.Addr.Family != AF_UNSPEC { |
|
482 from, err = anyToSockaddr(fd, &rsa) |
|
483 } |
|
484 return |
477 return |
485 } |
478 } |
486 |
479 |
487 func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) { |
|
488 _, err = SendmsgN(fd, p, oob, to, flags) |
|
489 return |
|
490 } |
|
491 |
|
492 //sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.__xnet_sendmsg |
480 //sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.__xnet_sendmsg |
493 |
481 |
494 func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) { |
482 func sendmsgN(fd int, iov []Iovec, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) { |
495 var ptr unsafe.Pointer |
|
496 var salen _Socklen |
|
497 if to != nil { |
|
498 ptr, salen, err = to.sockaddr() |
|
499 if err != nil { |
|
500 return 0, err |
|
501 } |
|
502 } |
|
503 var msg Msghdr |
483 var msg Msghdr |
504 msg.Name = (*byte)(unsafe.Pointer(ptr)) |
484 msg.Name = (*byte)(unsafe.Pointer(ptr)) |
505 msg.Namelen = uint32(salen) |
485 msg.Namelen = uint32(salen) |
506 var iov Iovec |
486 var dummy byte |
507 if len(p) > 0 { |
487 var empty bool |
508 iov.Base = (*int8)(unsafe.Pointer(&p[0])) |
|
509 iov.SetLen(len(p)) |
|
510 } |
|
511 var dummy int8 |
|
512 if len(oob) > 0 { |
488 if len(oob) > 0 { |
513 // send at least one normal byte |
489 // send at least one normal byte |
514 if len(p) == 0 { |
490 empty = emptyIovecs(iov) |
515 iov.Base = &dummy |
491 if empty { |
516 iov.SetLen(1) |
492 var iova [1]Iovec |
|
493 iova[0].Base = &dummy |
|
494 iova[0].SetLen(1) |
|
495 iov = iova[:] |
517 } |
496 } |
518 msg.Accrightslen = int32(len(oob)) |
497 msg.Accrightslen = int32(len(oob)) |
519 } |
498 } |
520 msg.Iov = &iov |
499 if len(iov) > 0 { |
521 msg.Iovlen = 1 |
500 msg.Iov = &iov[0] |
|
501 msg.SetIovlen(len(iov)) |
|
502 } |
522 if n, err = sendmsg(fd, &msg, flags); err != nil { |
503 if n, err = sendmsg(fd, &msg, flags); err != nil { |
523 return 0, err |
504 return 0, err |
524 } |
505 } |
525 if len(oob) > 0 && len(p) == 0 { |
506 if len(oob) > 0 && empty { |
526 n = 0 |
507 n = 0 |
527 } |
508 } |
528 return n, nil |
509 return n, nil |
529 } |
510 } |
530 |
511 |
660 //sys Nanosleep(time *Timespec, leftover *Timespec) (err error) |
642 //sys Nanosleep(time *Timespec, leftover *Timespec) (err error) |
661 //sys Open(path string, mode int, perm uint32) (fd int, err error) |
643 //sys Open(path string, mode int, perm uint32) (fd int, err error) |
662 //sys Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) |
644 //sys Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) |
663 //sys Pathconf(path string, name int) (val int, err error) |
645 //sys Pathconf(path string, name int) (val int, err error) |
664 //sys Pause() (err error) |
646 //sys Pause() (err error) |
665 //sys Pread(fd int, p []byte, offset int64) (n int, err error) |
647 //sys pread(fd int, p []byte, offset int64) (n int, err error) |
666 //sys Pwrite(fd int, p []byte, offset int64) (n int, err error) |
648 //sys pwrite(fd int, p []byte, offset int64) (n int, err error) |
667 //sys read(fd int, p []byte) (n int, err error) |
649 //sys read(fd int, p []byte) (n int, err error) |
668 //sys Readlink(path string, buf []byte) (n int, err error) |
650 //sys Readlink(path string, buf []byte) (n int, err error) |
669 //sys Rename(from string, to string) (err error) |
651 //sys Rename(from string, to string) (err error) |
670 //sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) |
652 //sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) |
671 //sys Rmdir(path string) (err error) |
653 //sys Rmdir(path string) (err error) |
742 } |
724 } |
743 |
725 |
744 func Munmap(b []byte) (err error) { |
726 func Munmap(b []byte) (err error) { |
745 return mapper.Munmap(b) |
727 return mapper.Munmap(b) |
746 } |
728 } |
|
729 |
|
730 // Event Ports |
|
731 |
|
732 type fileObjCookie struct { |
|
733 fobj *fileObj |
|
734 cookie interface{} |
|
735 } |
|
736 |
|
737 // EventPort provides a safe abstraction on top of Solaris/illumos Event Ports. |
|
738 type EventPort struct { |
|
739 port int |
|
740 mu sync.Mutex |
|
741 fds map[uintptr]*fileObjCookie |
|
742 paths map[string]*fileObjCookie |
|
743 // The user cookie presents an interesting challenge from a memory management perspective. |
|
744 // There are two paths by which we can discover that it is no longer in use: |
|
745 // 1. The user calls port_dissociate before any events fire |
|
746 // 2. An event fires and we return it to the user |
|
747 // The tricky situation is if the event has fired in the kernel but |
|
748 // the user hasn't requested/received it yet. |
|
749 // If the user wants to port_dissociate before the event has been processed, |
|
750 // we should handle things gracefully. To do so, we need to keep an extra |
|
751 // reference to the cookie around until the event is processed |
|
752 // thus the otherwise seemingly extraneous "cookies" map |
|
753 // The key of this map is a pointer to the corresponding &fCookie.cookie |
|
754 cookies map[*interface{}]*fileObjCookie |
|
755 } |
|
756 |
|
757 // PortEvent is an abstraction of the port_event C struct. |
|
758 // Compare Source against PORT_SOURCE_FILE or PORT_SOURCE_FD |
|
759 // to see if Path or Fd was the event source. The other will be |
|
760 // uninitialized. |
|
761 type PortEvent struct { |
|
762 Cookie interface{} |
|
763 Events int32 |
|
764 Fd uintptr |
|
765 Path string |
|
766 Source uint16 |
|
767 fobj *fileObj |
|
768 } |
|
769 |
|
770 // NewEventPort creates a new EventPort including the |
|
771 // underlying call to port_create(3c). |
|
772 func NewEventPort() (*EventPort, error) { |
|
773 port, err := port_create() |
|
774 if err != nil { |
|
775 return nil, err |
|
776 } |
|
777 e := &EventPort{ |
|
778 port: port, |
|
779 fds: make(map[uintptr]*fileObjCookie), |
|
780 paths: make(map[string]*fileObjCookie), |
|
781 cookies: make(map[*interface{}]*fileObjCookie), |
|
782 } |
|
783 return e, nil |
|
784 } |
|
785 |
|
786 //sys port_create() (n int, err error) |
|
787 //sys port_associate(port int, source int, object uintptr, events int, user *byte) (n int, err error) |
|
788 //sys port_dissociate(port int, source int, object uintptr) (n int, err error) |
|
789 //sys port_get(port int, pe *portEvent, timeout *Timespec) (n int, err error) |
|
790 //sys port_getn(port int, pe *portEvent, max uint32, nget *uint32, timeout *Timespec) (n int, err error) |
|
791 |
|
792 // Close closes the event port. |
|
793 func (e *EventPort) Close() error { |
|
794 e.mu.Lock() |
|
795 defer e.mu.Unlock() |
|
796 err := Close(e.port) |
|
797 if err != nil { |
|
798 return err |
|
799 } |
|
800 e.fds = nil |
|
801 e.paths = nil |
|
802 return nil |
|
803 } |
|
804 |
|
805 // PathIsWatched checks to see if path is associated with this EventPort. |
|
806 func (e *EventPort) PathIsWatched(path string) bool { |
|
807 e.mu.Lock() |
|
808 defer e.mu.Unlock() |
|
809 _, found := e.paths[path] |
|
810 return found |
|
811 } |
|
812 |
|
813 // FdIsWatched checks to see if fd is associated with this EventPort. |
|
814 func (e *EventPort) FdIsWatched(fd uintptr) bool { |
|
815 e.mu.Lock() |
|
816 defer e.mu.Unlock() |
|
817 _, found := e.fds[fd] |
|
818 return found |
|
819 } |
|
820 |
|
821 // AssociatePath wraps port_associate(3c) for a filesystem path including |
|
822 // creating the necessary file_obj from the provided stat information. |
|
823 func (e *EventPort) AssociatePath(path string, stat os.FileInfo, events int, cookie interface{}) error { |
|
824 e.mu.Lock() |
|
825 defer e.mu.Unlock() |
|
826 if _, found := e.paths[path]; found { |
|
827 return fmt.Errorf("%v is already associated with this Event Port", path) |
|
828 } |
|
829 fobj, err := createFileObj(path, stat) |
|
830 if err != nil { |
|
831 return err |
|
832 } |
|
833 fCookie := &fileObjCookie{fobj, cookie} |
|
834 _, err = port_associate(e.port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(fobj)), events, (*byte)(unsafe.Pointer(&fCookie.cookie))) |
|
835 if err != nil { |
|
836 return err |
|
837 } |
|
838 e.paths[path] = fCookie |
|
839 e.cookies[&fCookie.cookie] = fCookie |
|
840 return nil |
|
841 } |
|
842 |
|
843 // DissociatePath wraps port_dissociate(3c) for a filesystem path. |
|
844 func (e *EventPort) DissociatePath(path string) error { |
|
845 e.mu.Lock() |
|
846 defer e.mu.Unlock() |
|
847 f, ok := e.paths[path] |
|
848 if !ok { |
|
849 return fmt.Errorf("%v is not associated with this Event Port", path) |
|
850 } |
|
851 _, err := port_dissociate(e.port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(f.fobj))) |
|
852 // If the path is no longer associated with this event port (ENOENT) |
|
853 // we should delete it from our map. We can still return ENOENT to the caller. |
|
854 // But we need to save the cookie |
|
855 if err != nil && err != ENOENT { |
|
856 return err |
|
857 } |
|
858 if err == nil { |
|
859 // dissociate was successful, safe to delete the cookie |
|
860 fCookie := e.paths[path] |
|
861 delete(e.cookies, &fCookie.cookie) |
|
862 } |
|
863 delete(e.paths, path) |
|
864 return err |
|
865 } |
|
866 |
|
867 // AssociateFd wraps calls to port_associate(3c) on file descriptors. |
|
868 func (e *EventPort) AssociateFd(fd uintptr, events int, cookie interface{}) error { |
|
869 e.mu.Lock() |
|
870 defer e.mu.Unlock() |
|
871 if _, found := e.fds[fd]; found { |
|
872 return fmt.Errorf("%v is already associated with this Event Port", fd) |
|
873 } |
|
874 fCookie := &fileObjCookie{nil, cookie} |
|
875 _, err := port_associate(e.port, PORT_SOURCE_FD, fd, events, (*byte)(unsafe.Pointer(&fCookie.cookie))) |
|
876 if err != nil { |
|
877 return err |
|
878 } |
|
879 e.fds[fd] = fCookie |
|
880 e.cookies[&fCookie.cookie] = fCookie |
|
881 return nil |
|
882 } |
|
883 |
|
884 // DissociateFd wraps calls to port_dissociate(3c) on file descriptors. |
|
885 func (e *EventPort) DissociateFd(fd uintptr) error { |
|
886 e.mu.Lock() |
|
887 defer e.mu.Unlock() |
|
888 _, ok := e.fds[fd] |
|
889 if !ok { |
|
890 return fmt.Errorf("%v is not associated with this Event Port", fd) |
|
891 } |
|
892 _, err := port_dissociate(e.port, PORT_SOURCE_FD, fd) |
|
893 if err != nil && err != ENOENT { |
|
894 return err |
|
895 } |
|
896 if err == nil { |
|
897 // dissociate was successful, safe to delete the cookie |
|
898 fCookie := e.fds[fd] |
|
899 delete(e.cookies, &fCookie.cookie) |
|
900 } |
|
901 delete(e.fds, fd) |
|
902 return err |
|
903 } |
|
904 |
|
905 func createFileObj(name string, stat os.FileInfo) (*fileObj, error) { |
|
906 fobj := new(fileObj) |
|
907 bs, err := ByteSliceFromString(name) |
|
908 if err != nil { |
|
909 return nil, err |
|
910 } |
|
911 fobj.Name = (*int8)(unsafe.Pointer(&bs[0])) |
|
912 s := stat.Sys().(*syscall.Stat_t) |
|
913 fobj.Atim.Sec = s.Atim.Sec |
|
914 fobj.Atim.Nsec = s.Atim.Nsec |
|
915 fobj.Mtim.Sec = s.Mtim.Sec |
|
916 fobj.Mtim.Nsec = s.Mtim.Nsec |
|
917 fobj.Ctim.Sec = s.Ctim.Sec |
|
918 fobj.Ctim.Nsec = s.Ctim.Nsec |
|
919 return fobj, nil |
|
920 } |
|
921 |
|
922 // GetOne wraps port_get(3c) and returns a single PortEvent. |
|
923 func (e *EventPort) GetOne(t *Timespec) (*PortEvent, error) { |
|
924 pe := new(portEvent) |
|
925 _, err := port_get(e.port, pe, t) |
|
926 if err != nil { |
|
927 return nil, err |
|
928 } |
|
929 p := new(PortEvent) |
|
930 e.mu.Lock() |
|
931 defer e.mu.Unlock() |
|
932 e.peIntToExt(pe, p) |
|
933 return p, nil |
|
934 } |
|
935 |
|
936 // peIntToExt converts a cgo portEvent struct into the friendlier PortEvent |
|
937 // NOTE: Always call this function while holding the e.mu mutex |
|
938 func (e *EventPort) peIntToExt(peInt *portEvent, peExt *PortEvent) { |
|
939 peExt.Events = peInt.Events |
|
940 peExt.Source = peInt.Source |
|
941 cookie := (*interface{})(unsafe.Pointer(peInt.User)) |
|
942 peExt.Cookie = *cookie |
|
943 switch peInt.Source { |
|
944 case PORT_SOURCE_FD: |
|
945 delete(e.cookies, cookie) |
|
946 peExt.Fd = uintptr(peInt.Object) |
|
947 // Only remove the fds entry if it exists and this cookie matches |
|
948 if fobj, ok := e.fds[peExt.Fd]; ok { |
|
949 if &fobj.cookie == cookie { |
|
950 delete(e.fds, peExt.Fd) |
|
951 } |
|
952 } |
|
953 case PORT_SOURCE_FILE: |
|
954 if fCookie, ok := e.cookies[cookie]; ok && uintptr(unsafe.Pointer(fCookie.fobj)) == uintptr(peInt.Object) { |
|
955 // Use our stashed reference rather than using unsafe on what we got back |
|
956 // the unsafe version would be (*fileObj)(unsafe.Pointer(uintptr(peInt.Object))) |
|
957 peExt.fobj = fCookie.fobj |
|
958 } else { |
|
959 panic("mismanaged memory") |
|
960 } |
|
961 delete(e.cookies, cookie) |
|
962 peExt.Path = BytePtrToString((*byte)(unsafe.Pointer(peExt.fobj.Name))) |
|
963 // Only remove the paths entry if it exists and this cookie matches |
|
964 if fobj, ok := e.paths[peExt.Path]; ok { |
|
965 if &fobj.cookie == cookie { |
|
966 delete(e.paths, peExt.Path) |
|
967 } |
|
968 } |
|
969 } |
|
970 } |
|
971 |
|
972 // Pending wraps port_getn(3c) and returns how many events are pending. |
|
973 func (e *EventPort) Pending() (int, error) { |
|
974 var n uint32 = 0 |
|
975 _, err := port_getn(e.port, nil, 0, &n, nil) |
|
976 return int(n), err |
|
977 } |
|
978 |
|
979 // Get wraps port_getn(3c) and fills a slice of PortEvent. |
|
980 // It will block until either min events have been received |
|
981 // or the timeout has been exceeded. It will return how many |
|
982 // events were actually received along with any error information. |
|
983 func (e *EventPort) Get(s []PortEvent, min int, timeout *Timespec) (int, error) { |
|
984 if min == 0 { |
|
985 return 0, fmt.Errorf("need to request at least one event or use Pending() instead") |
|
986 } |
|
987 if len(s) < min { |
|
988 return 0, fmt.Errorf("len(s) (%d) is less than min events requested (%d)", len(s), min) |
|
989 } |
|
990 got := uint32(min) |
|
991 max := uint32(len(s)) |
|
992 var err error |
|
993 ps := make([]portEvent, max, max) |
|
994 _, err = port_getn(e.port, &ps[0], max, &got, timeout) |
|
995 // got will be trustworthy with ETIME, but not any other error. |
|
996 if err != nil && err != ETIME { |
|
997 return 0, err |
|
998 } |
|
999 e.mu.Lock() |
|
1000 defer e.mu.Unlock() |
|
1001 for i := 0; i < int(got); i++ { |
|
1002 e.peIntToExt(&ps[i], &s[i]) |
|
1003 } |
|
1004 return int(got), err |
|
1005 } |