github.com/dshulyak/uring@v0.0.0-20210209113719-1b2ec51f1542/setup.go (about)

     1  package uring
     2  
     3  import (
     4  	"fmt"
     5  	"syscall"
     6  	"unsafe"
     7  )
     8  
     9  const (
    10  	MinSize = 2
    11  	MaxSize = 4096
    12  )
    13  
    14  func Setup(size uint, params *IOUringParams) (*Ring, error) {
    15  	var ring Ring
    16  	if params != nil {
    17  		ring.params = *params
    18  	}
    19  	if err := setup(&ring, size, &ring.params); err != nil {
    20  		return nil, err
    21  	}
    22  	return &ring, nil
    23  }
    24  
    25  func setup(ring *Ring, size uint, p *IOUringParams) error {
    26  	fd, _, errno := syscall.Syscall(IO_URING_SETUP, uintptr(size), uintptr(unsafe.Pointer(p)), 0)
    27  	if errno != 0 {
    28  		return fmt.Errorf("IO_URING_SETUP %w", error(errno))
    29  	}
    30  	ring.fd = int(fd)
    31  
    32  	sqsize := p.SQOff.Array + p.SQEntries*uint32(4)
    33  	cqsize := p.CQOff.CQEs + p.CQEntries*uint32(cqeSize)
    34  	isSingleMap := p.Features&IORING_FEAT_SINGLE_MMAP > 0
    35  	if isSingleMap {
    36  		if cqsize > sqsize {
    37  			sqsize = cqsize
    38  		}
    39  	}
    40  
    41  	data, err := syscall.Mmap(int(fd), IORING_OFF_SQ_RING, int(sqsize),
    42  		syscall.PROT_READ|syscall.PROT_WRITE,
    43  		syscall.MAP_SHARED|syscall.MAP_POPULATE)
    44  	if err != nil {
    45  		return err
    46  	}
    47  	ring.sqData = data
    48  	pointer := unsafe.Pointer(&data[0])
    49  
    50  	ring.sq.head = (*uint32)(unsafe.Pointer(uintptr(pointer) + uintptr(p.SQOff.Head)))
    51  	ring.sq.tail = (*uint32)(unsafe.Pointer(uintptr(pointer) + uintptr(p.SQOff.Tail)))
    52  	ring.sq.ringMask = (*uint32)(unsafe.Pointer(uintptr(pointer) + uintptr(p.SQOff.RingMask)))
    53  	ring.sq.ringEntries = (*uint32)(unsafe.Pointer(uintptr(pointer) + uintptr(p.SQOff.RingEntries)))
    54  	ring.sq.flags = (*uint32)(unsafe.Pointer(uintptr(pointer) + uintptr(p.SQOff.Flags)))
    55  	ring.sq.dropped = (*uint32)(unsafe.Pointer(uintptr(pointer) + uintptr(p.SQOff.Dropped)))
    56  	ring.sq.array = uint32Array(unsafe.Pointer(uintptr(pointer) + uintptr(p.SQOff.Array)))
    57  
    58  	if !isSingleMap {
    59  		data, err = syscall.Mmap(int(fd), IORING_OFF_CQ_RING, int(cqsize),
    60  			syscall.PROT_READ|syscall.PROT_WRITE,
    61  			syscall.MAP_SHARED|syscall.MAP_POPULATE)
    62  		if err != nil {
    63  			return err
    64  		}
    65  		ring.cqData = data
    66  		pointer = unsafe.Pointer(&data[0])
    67  	}
    68  
    69  	ring.cq.head = (*uint32)(unsafe.Pointer(uintptr(pointer) + uintptr(p.CQOff.Head)))
    70  	ring.cq.tail = (*uint32)(unsafe.Pointer(uintptr(pointer) + uintptr(p.CQOff.Tail)))
    71  	ring.cq.ringmask = (*uint32)(unsafe.Pointer(uintptr(pointer) + uintptr(p.CQOff.RingMask)))
    72  	ring.cq.ringEntries = (*uint32)(unsafe.Pointer(uintptr(pointer) + uintptr(p.CQOff.RingEntries)))
    73  	ring.cq.overflow = (*uint32)(unsafe.Pointer(uintptr(pointer) + uintptr(p.CQOff.Overflow)))
    74  	ring.cq.cqes = cqeArray(unsafe.Pointer(uintptr(pointer) + uintptr(p.CQOff.CQEs)))
    75  	if p.CQOff.Flags != 0 {
    76  		ring.cq.flags = (*uint32)(unsafe.Pointer(uintptr(pointer) + uintptr(p.CQOff.Flags)))
    77  	}
    78  
    79  	entries, err := syscall.Mmap(int(fd), IORING_OFF_SQES,
    80  		int(p.SQEntries)*int(sqeSize),
    81  		syscall.PROT_READ|syscall.PROT_WRITE,
    82  		syscall.MAP_SHARED|syscall.MAP_POPULATE)
    83  
    84  	if err != nil {
    85  		return err
    86  	}
    87  	ring.sqArrayData = entries
    88  	ring.sq.sqes = sqeArray(unsafe.Pointer(&entries[0]))
    89  	return nil
    90  }
    91  
    92  func (r *Ring) Close() (err error) {
    93  	if r.cqData != nil {
    94  		ret := syscall.Munmap(r.cqData)
    95  		if err == nil {
    96  			err = ret
    97  		}
    98  		if ret == nil {
    99  			r.cqData = nil
   100  		}
   101  	}
   102  	if r.sqData != nil {
   103  		ret := syscall.Munmap(r.sqData)
   104  		if err == nil {
   105  			err = ret
   106  		}
   107  		if ret == nil {
   108  			r.sqData = nil
   109  		}
   110  	}
   111  	if r.sqArrayData != nil {
   112  		ret := syscall.Munmap(r.sqArrayData)
   113  		if err == nil {
   114  			err = ret
   115  		}
   116  		if ret == nil {
   117  			r.sqArrayData = nil
   118  		}
   119  	}
   120  	if r.fd != 0 {
   121  		ret := syscall.Close(r.fd)
   122  		if err == nil {
   123  			err = ret
   124  		}
   125  		if ret == nil {
   126  			r.fd = 0
   127  		}
   128  	}
   129  	return
   130  }