github.com/kazu/loncha@v0.6.3/list_head/list_head.go (about)

     1  // Copyright 2019 Kazuhisa TAKEI<xtakei@rytr.jp>. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package loncha/list_head is like a kernel's LIST_HEAD
     6  // list_head is used by loncha/gen/containers_list
     7  package list_head
     8  
     9  import (
    10  	"errors"
    11  	"fmt"
    12  	"os"
    13  	"strings"
    14  	"sync/atomic"
    15  	"unsafe"
    16  )
    17  
    18  var (
    19  	MODE_CONCURRENT      bool = false
    20  	PANIC_NEXT_IS_MARKED bool = false
    21  )
    22  
    23  type ListHead struct {
    24  	prev *ListHead
    25  	next *ListHead
    26  }
    27  
    28  func GetConcurrentMode() bool {
    29  	return MODE_CONCURRENT
    30  }
    31  
    32  func (head *ListHead) Init() {
    33  	head.prev = head
    34  	head.next = head
    35  }
    36  
    37  func (head *ListHead) Prev() *ListHead {
    38  	prev := atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&head.prev)))
    39  	return (*ListHead)(prev)
    40  }
    41  
    42  func (head *ListHead) DirectNext() *ListHead {
    43  	return head.next
    44  }
    45  
    46  func (head *ListHead) PtrNext() **ListHead {
    47  	//return atomic.LoadPointer(&head.next)
    48  	return &head.next
    49  }
    50  
    51  func (head *ListHead) isDeleted() (deleted bool) {
    52  	/*defer func() {
    53  		if perr := recover(); perr != nil {
    54  			fmt.Printf("\nisDelete(): recover %+v\n", head)
    55  		}
    56  	}()*/
    57  	if head == nil {
    58  		panic("isDelete invalid")
    59  	}
    60  	next := atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&head.next)))
    61  
    62  	if next == nil {
    63  		panic("isDelete next is nil")
    64  		return false
    65  	}
    66  
    67  	if uintptr(next)&1 > 0 {
    68  		return true
    69  	}
    70  	return false
    71  
    72  }
    73  
    74  func (list *ListHead) DeleteMarked() {
    75  
    76  	head := list.Front()
    77  	//fmt.Printf("Info: DeleteMarked START %p\n", head)
    78  	elm := head
    79  	old := elm
    80  
    81  	for {
    82  		// mark
    83  		old = elm
    84  		//atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&elm)), unsafe.Pointer(elm.next)) // elm = elm.next // FIXME: race condition 413, 85
    85  		if !atomic.CompareAndSwapPointer(
    86  			(*unsafe.Pointer)(unsafe.Pointer(&elm)),
    87  			unsafe.Pointer(old),
    88  			unsafe.Pointer(elm.next)) {
    89  
    90  			fmt.Printf("WARN: fail cas for DeleteMarked loop\n")
    91  			continue
    92  		}
    93  
    94  		if old == elm {
    95  			//fmt.Printf("Info: DeleteMarked END %p\n", head)
    96  			return
    97  		}
    98  
    99  		if elm.isDeleted() {
   100  			elm.deleteDirect(old)
   101  			//fmt.Printf("Info: DeleteMarked STOP/RESTART %p\n", head)
   102  			elm = head
   103  			//}
   104  		}
   105  
   106  	}
   107  
   108  }
   109  
   110  func (head *ListHead) Next() (nextElement *ListHead) {
   111  
   112  	if !MODE_CONCURRENT {
   113  		return head.next
   114  	}
   115  
   116  	return head.Next1()
   117  }
   118  
   119  func (head *ListHead) Next1() (nextElement *ListHead) {
   120  	defer func() {
   121  		if nextElement == nil {
   122  			nextElement = head
   123  		}
   124  
   125  		//fmt.Printf("\thead(%s).next1() => %s\n", head.P(), nextElement.P())
   126  
   127  	}()
   128  
   129  	//nextElement = head.next1()
   130  retry:
   131  	nextElement = head.next3()
   132  	if head.next != nextElement && nextElement != nil {
   133  		//fmt.Printf("head.next=%s nextElement=%s\n", head.Pp(), nextElement.Pp())
   134  		goto retry
   135  	}
   136  	return
   137  }
   138  
   139  // return nil on last of list
   140  func (head *ListHead) next1() (nextElement *ListHead) {
   141  
   142  	uptr := unsafe.Pointer(head.next)
   143  	next := atomic.LoadPointer(&uptr)
   144  
   145  	hptr := unsafe.Pointer(head)
   146  	pHead := atomic.LoadPointer(&hptr)
   147  
   148  	EqualWithMark := func(src, dst unsafe.Pointer) bool {
   149  		if src == nil {
   150  			return true
   151  		}
   152  
   153  		if uintptr(src) == uintptr(dst) {
   154  			return true
   155  		}
   156  
   157  		if uintptr(src) > uintptr(dst) && uintptr(src)-uintptr(dst) <= 1 {
   158  			return true
   159  		}
   160  		if uintptr(src) < uintptr(dst) && uintptr(dst)-uintptr(src) <= 1 {
   161  			return true
   162  		}
   163  		return false
   164  	}
   165  
   166  	for !EqualWithMark(next, pHead) {
   167  		//	for next != pHead {
   168  
   169  		if uintptr(next)&1 > 0 {
   170  			nextElement = (*ListHead)(unsafe.Pointer(uintptr(next) ^ 1))
   171  			//Log(true).Debug("list.next1() is marked skip ", zap.String("head", head.P()))
   172  			return nextElement.next1()
   173  		}
   174  		nextElement = (*ListHead)(next)
   175  
   176  		if nextElement.isDeleted() {
   177  			pHead = atomic.LoadPointer(&uptr)
   178  			atomic.CompareAndSwapPointer(&uptr, next, unsafe.Pointer(nextElement.next1()))
   179  			next = atomic.LoadPointer(&uptr)
   180  			if next != nil {
   181  				// Log(true).Debug("list.next1() is marked(next loop) ",
   182  				// 	zap.String("head", head.P()),
   183  				// 	zap.String("next", ((*ListHead)(next)).P()),
   184  				// )
   185  			} else {
   186  				// Log(true).Debug("list.next1() is marked(next loop) ",
   187  				// 	zap.String("head", head.P()),
   188  				// 	zap.String("next", "nil"),
   189  				// )
   190  			}
   191  		} else {
   192  			// Log(true).Debug("list.next1() not marking ",
   193  			// 	zap.String("head", head.P()),
   194  			// 	zap.String("next", nextElement.P()))
   195  
   196  			return nextElement
   197  		}
   198  
   199  	}
   200  
   201  	// Log(true).Debug("list.next1() last position ",
   202  	// 	zap.String("head", head.P()),
   203  	// )
   204  
   205  	return nil
   206  }
   207  
   208  func (head *ListHead) next3() *ListHead {
   209  
   210  	headNext := atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&head.next)))
   211  
   212  	if unsafe.Pointer(head) == headNext {
   213  		return nil
   214  	}
   215  	if unsafe.Pointer(head) == unsafe.Pointer(uintptr(headNext)^1) {
   216  		return nil
   217  	}
   218  
   219  	if head.isDeleted() {
   220  		if PANIC_NEXT_IS_MARKED {
   221  			head.isDeleted()
   222  			panic("next3 must not isDeleted()")
   223  		}
   224  
   225  		fmt.Fprintf(os.Stderr, "WARN: return marked value because next is marked\n")
   226  		return nil
   227  
   228  	}
   229  	if (*ListHead)(headNext).isDeleted() {
   230  		head.DeleteMarked()
   231  	}
   232  
   233  	return (*ListHead)(headNext)
   234  
   235  }
   236  
   237  func (head *ListHead) next2() (nextElement *ListHead) {
   238  
   239  RESTART:
   240  
   241  	uptr := unsafe.Pointer(head.next)
   242  	next := atomic.LoadPointer(&uptr)
   243  
   244  	hptr := unsafe.Pointer(head)
   245  	pHead := atomic.LoadPointer(&hptr)
   246  
   247  	EqualWithMark := func(src, dst unsafe.Pointer) bool {
   248  		if src == nil {
   249  			return true
   250  		}
   251  
   252  		if uintptr(src) == uintptr(dst) {
   253  			return true
   254  		}
   255  
   256  		if uintptr(src) > uintptr(dst) && uintptr(src)-uintptr(dst) <= 1 {
   257  			return true
   258  		}
   259  		if uintptr(src) < uintptr(dst) && uintptr(dst)-uintptr(src) <= 1 {
   260  			return true
   261  		}
   262  		return false
   263  	}
   264  
   265  	for !EqualWithMark(next, pHead) {
   266  		//	for next != pHead {
   267  
   268  		if uintptr(next)&1 > 0 {
   269  			head.DeleteMarked()
   270  			goto RESTART
   271  			//nextElement = (*ListHead)(unsafe.Pointer(uintptr(next) ^ 1))
   272  			//return nextElement.next1()
   273  		}
   274  		nextElement = (*ListHead)(next)
   275  
   276  		if nextElement.isDeleted() {
   277  			head.DeleteMarked()
   278  			goto RESTART
   279  		} else {
   280  			return nextElement
   281  		}
   282  
   283  	}
   284  
   285  	return nil
   286  
   287  }
   288  
   289  func (head *ListHead) Next0() (next *ListHead) {
   290  
   291  	if !MODE_CONCURRENT {
   292  		next = head.next
   293  		return
   294  	}
   295  
   296  	cptr := unsafe.Pointer(head)
   297  	curPtr := atomic.LoadPointer(&cptr)
   298  	//_ = cur
   299  
   300  	ptr := unsafe.Pointer(head.next)
   301  	nextPtr := atomic.LoadPointer(&ptr)
   302  
   303  	cur := (*ListHead)(curPtr)
   304  	next = (*ListHead)(nextPtr)
   305  
   306  	if cur == next {
   307  		return
   308  	}
   309  	/*
   310  		if next.isDeleted() {
   311  			return next.Next()
   312  		}
   313  	*/
   314  	if cur.isDeleted() {
   315  		nextPtr = unsafe.Pointer(uintptr(nextPtr) ^ 1)
   316  		next = (*ListHead)(nextPtr)
   317  		if cur == next {
   318  			return
   319  		}
   320  		next = next.Next()
   321  	}
   322  	return
   323  
   324  }
   325  
   326  func listAdd(new, prev, next *ListHead) {
   327  	if prev != next {
   328  		next.prev, new.next, new.prev, prev.next = new, next, prev, new
   329  	} else {
   330  		prev.next, new.prev = new, prev
   331  	}
   332  }
   333  
   334  func listAddWitCas(new, prev, next *ListHead) (err error) {
   335  	if prev != next {
   336  		//new.next = next
   337  		atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&new.next)),
   338  			unsafe.Pointer(next))
   339  	}
   340  
   341  	if atomic.CompareAndSwapPointer(
   342  		(*unsafe.Pointer)(unsafe.Pointer(&prev.next)),
   343  		unsafe.Pointer(next),
   344  		unsafe.Pointer(new)) {
   345  		if prev != next {
   346  			//next.prev, new.prev = new, prev
   347  			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&next.prev)),
   348  				unsafe.Pointer(new))
   349  			//new.prev = prev
   350  			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&new.prev)),
   351  				unsafe.Pointer(prev))
   352  		} else {
   353  			//new.prev = prev
   354  			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&new.prev)),
   355  				unsafe.Pointer(prev))
   356  		}
   357  		return
   358  	}
   359  	return //errors.New("cas conflict")
   360  	return fmt.Errorf("listAddWithCas() fail retry: new=%s prev=%s next=%s",
   361  		new.Pp(),
   362  		prev.Pp(),
   363  		next.Pp())
   364  
   365  }
   366  
   367  func (head *ListHead) Add(new *ListHead) {
   368  	if MODE_CONCURRENT {
   369  		for true {
   370  			//err := listAddWitCas(new, head, (*ListHead)(headNext))
   371  			err := listAddWitCas(new,
   372  				head,
   373  				(*ListHead)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&head.next)))))
   374  			if err == nil {
   375  				break
   376  			}
   377  			fmt.Printf("Add(): retry err=%s\n", err.Error())
   378  		}
   379  		return
   380  	}
   381  	listAdd(new, head, head.next)
   382  }
   383  
   384  func (l *ListHead) MarkForDelete() (err error) {
   385  
   386  	if atomic.CompareAndSwapPointer(
   387  		(*unsafe.Pointer)(unsafe.Pointer(&l.next)),
   388  		unsafe.Pointer(l.next),
   389  		unsafe.Pointer(uintptr(unsafe.Pointer(l.next))|1)) {
   390  		return
   391  	}
   392  	return errors.New("cas conflict(fail mark)")
   393  }
   394  
   395  func (l *ListHead) DeleteWithCas(prev *ListHead) (err error) {
   396  	use_mark := true
   397  
   398  	head := l.Front()
   399  	_ = head
   400  	defer func() {
   401  		if err == nil {
   402  			//if ContainOf(head, l) {
   403  			//	panic("????!!!")
   404  			//}
   405  		}
   406  	}()
   407  
   408  	/*
   409  		defer func() {
   410  
   411  			if perr := recover(); perr != nil {
   412  				fmt.Printf("panic: retry l=%p\n", l)
   413  				err = fmt.Errorf("panic: retry l=%p\n", l)
   414  				return
   415  			}
   416  			if err == nil {
   417  				fmt.Printf("Success: l=%p\n", l)
   418  				l.Init()
   419  			}
   420  
   421  			return
   422  		}()
   423  	*/
   424  	if l.IsFirst() {
   425  		//l.next.prev = l.next
   426  		//panic("first element cannot delete")
   427  		return errors.New("first element cannot delete")
   428  	}
   429  	if use_mark {
   430  		err = l.MarkForDelete() // FIXME: race condition 79
   431  		if err != nil {
   432  			return err
   433  		}
   434  	}
   435  
   436  	if l.deleteDirect(prev) {
   437  		return
   438  	} else {
   439  		//l.DeleteMarked()
   440  		return errors.New("retry from list first")
   441  	}
   442  
   443  	return fmt.Errorf("Delete() fail retry: l.prev=%s l=%s l.prev.isDeleted=%v l.IsLast()=%v",
   444  		l.prev.Pp(),
   445  		l.Pp(),
   446  		l.prev.isDeleted(),
   447  		l.IsLast())
   448  }
   449  
   450  func (l *ListHead) deleteDirect(oprev *ListHead) (success bool) {
   451  	prev := (*ListHead)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&l.prev)))) // prev := l.prev // FIXME: race condition 452
   452  	if oprev != nil {
   453  		atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&prev)), unsafe.Pointer(oprev)) // prev = oprev
   454  	}
   455  
   456  	success = false
   457  	defer func() {
   458  		if success {
   459  			//l.next, l.prev = l, l
   460  			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&l.next)),
   461  				unsafe.Pointer(l))
   462  			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&l.prev)),
   463  				unsafe.Pointer(l))
   464  		}
   465  	}()
   466  
   467  	if l.isLastWithMarked() {
   468  		if atomic.CompareAndSwapPointer(
   469  			(*unsafe.Pointer)(unsafe.Pointer(&prev.next)),
   470  			//unsafe.Pointer(uintptr(unsafe.Pointer(l.next))^1),
   471  			unsafe.Pointer(l),
   472  			unsafe.Pointer(prev)) {
   473  			success = true
   474  			return
   475  		}
   476  		return
   477  	}
   478  
   479  	if atomic.CompareAndSwapPointer(
   480  		(*unsafe.Pointer)(unsafe.Pointer(&prev.next)),
   481  		unsafe.Pointer(l),
   482  		unsafe.Pointer(uintptr(unsafe.Pointer(l.next))^1)) {
   483  		//		unsafe.Pointer(l.prev)) {
   484  		success = true
   485  		if l.isLastWithMarked() {
   486  			panic("????")
   487  		} else {
   488  			// prev.next.prev = l.prev
   489  			atomic.CompareAndSwapPointer(
   490  				(*unsafe.Pointer)(unsafe.Pointer(&prev.next.prev)),
   491  				unsafe.Pointer(l),
   492  				unsafe.Pointer(l.prev))
   493  
   494  			return
   495  		}
   496  	}
   497  
   498  	return
   499  }
   500  
   501  func (l *ListHead) Pp() string {
   502  
   503  	return fmt.Sprintf("%p{prev: %p, next:%p, len: %d}",
   504  		l,
   505  		atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&l.prev))), //l.prev,
   506  		atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&l.next))), //l.next,
   507  		l.Len()) // FIXME: race condition 350
   508  }
   509  
   510  func (l *ListHead) P() string {
   511  
   512  	return fmt.Sprintf("%p{prev: %p, next:%p}",
   513  		l,
   514  		atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&l.prev))), //l.prev,
   515  		atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&l.next)))) //l.next)
   516  }
   517  
   518  func (l *ListHead) Delete() (result *ListHead) {
   519  	/*
   520  		defer func() {
   521  			if perr := recover(); perr != nil {
   522  				fmt.Printf("panic: retry l=%p\n", l)
   523  				if !MODE_CONCURRENT {
   524  					panic(perr)
   525  				}
   526  				for true {
   527  					err := l.DeleteWithCas()
   528  					if err == nil {
   529  						break
   530  					}
   531  					fmt.Printf("Delete() err=%s\n", err.Error())
   532  				}
   533  				l.Init()
   534  				result = l.next
   535  			}
   536  
   537  		}()
   538  	*/
   539  	if MODE_CONCURRENT {
   540  		for true {
   541  			//			err := l.DeleteWithCas(l.prev)
   542  			err := l.DeleteWithCas((*ListHead)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&l.prev)))))
   543  			if err == nil {
   544  				break
   545  			}
   546  			fmt.Printf("err=%s\n", err.Error())
   547  			return nil
   548  		}
   549  	} else {
   550  
   551  		if l.IsFirst() {
   552  			l.next.prev = l.next
   553  		} else if l.IsLast() {
   554  			l.prev.next = l.prev
   555  		} else {
   556  			l.next.prev, l.prev.next = l.prev, l.next
   557  		}
   558  	}
   559  	// l.next, l.prev = l, l // FIXME: race condition 56
   560  	atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&l.next)), unsafe.Pointer(l))
   561  	atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&l.prev)), unsafe.Pointer(l))
   562  	return (*ListHead)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&l.next)))) //l.next
   563  
   564  }
   565  
   566  func (l *ListHead) Empty() bool {
   567  	return l.next == l
   568  }
   569  
   570  func (l *ListHead) IsLast() bool {
   571  	return l.Next() == l
   572  }
   573  
   574  func (l *ListHead) isLastWithMarked() bool {
   575  	//return l.Next() == l
   576  	if !l.isDeleted() {
   577  		return l.next == l
   578  	}
   579  
   580  	return unsafe.Pointer(l) == unsafe.Pointer(uintptr(unsafe.Pointer(l.next))^1)
   581  
   582  }
   583  
   584  func (l *ListHead) IsFirst() bool {
   585  	prev := atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&l.prev)))
   586  
   587  	return prev == unsafe.Pointer(l) // l.prev == l // FIXME: race condition ? :350, 358
   588  }
   589  
   590  func (l *ListHead) Len() (cnt int) {
   591  
   592  	cnt = 0
   593  	for s := l; s.Prev() != s; s = s.Prev() {
   594  		cnt++
   595  	}
   596  
   597  	if l.isDeleted() {
   598  		return cnt
   599  	}
   600  
   601  	for s := l; s.Next() != s; s = s.Next() {
   602  		cnt++
   603  		//fmt.Printf("\t\ts=%s cnt=%d\n", s.P(), cnt)
   604  	}
   605  
   606  	return cnt
   607  }
   608  
   609  func (l *ListHead) Front() (head *ListHead) {
   610  
   611  	for head = l; head.Prev() != head; head = head.Prev() {
   612  		if head.IsFirst() {
   613  			return head
   614  		}
   615  	}
   616  	//panic("front not found")
   617  	return
   618  }
   619  
   620  func (l *ListHead) Back() (head *ListHead) {
   621  
   622  	for head = l; head.Next() != head; head = head.Next() {
   623  		if head.IsLast() {
   624  			return head
   625  		}
   626  	}
   627  	//panic("back not found")
   628  	return
   629  }
   630  
   631  type Cursor struct {
   632  	Pos *ListHead
   633  }
   634  
   635  func (l *ListHead) Cursor() Cursor {
   636  
   637  	return Cursor{Pos: l}
   638  }
   639  
   640  func (cur *Cursor) Next() bool {
   641  
   642  	if cur.Pos == cur.Pos.Next() {
   643  		return false
   644  	}
   645  	cur.Pos = cur.Pos.Next()
   646  	return true
   647  
   648  }
   649  
   650  func ContainOf(head, elm *ListHead) bool {
   651  
   652  	c := head.Cursor()
   653  
   654  	for c.Next() {
   655  		if c.Pos == elm {
   656  			return true
   657  		}
   658  	}
   659  
   660  	return false
   661  }
   662  
   663  func (head *ListHead) DumpAll() string {
   664  
   665  	c := head.Cursor()
   666  	cnt := 1
   667  	var b strings.Builder
   668  	for c.Next() {
   669  		for i := 0; i < cnt; i++ {
   670  			b.WriteString("\t")
   671  		}
   672  		b.WriteString(c.Pos.P())
   673  		b.WriteString("\n")
   674  	}
   675  
   676  	return b.String()
   677  }
   678  
   679  func (head *ListHead) DumpAllWithMark() string {
   680  
   681  	cnt := 1
   682  	var b strings.Builder
   683  
   684  	cur := head
   685  	prev := cur
   686  
   687  	EqualWithMark := func(src, dst unsafe.Pointer) bool {
   688  		if src == nil {
   689  			return true
   690  		}
   691  
   692  		if uintptr(src) == uintptr(dst) {
   693  			return true
   694  		}
   695  
   696  		if uintptr(src) > uintptr(dst) && uintptr(src)-uintptr(dst) <= 1 {
   697  			return true
   698  		}
   699  		if uintptr(src) < uintptr(dst) && uintptr(dst)-uintptr(src) <= 1 {
   700  			return true
   701  		}
   702  		return false
   703  	}
   704  	for i := 0; i < cnt; i++ {
   705  		b.WriteString("\t")
   706  	}
   707  	b.WriteString(cur.P())
   708  	b.WriteString("\n")
   709  	cnt++
   710  
   711  	for {
   712  		prev = cur
   713  		//cur = prev.next
   714  		if prev.isDeleted() {
   715  			cur = (*ListHead)(unsafe.Pointer(uintptr(unsafe.Pointer(prev.next)) ^ 1))
   716  		} else {
   717  			cur = prev.next
   718  		}
   719  
   720  		for i := 0; i < cnt; i++ {
   721  			b.WriteString("\t")
   722  		}
   723  		b.WriteString(cur.P())
   724  		b.WriteString("\n")
   725  
   726  		if EqualWithMark(unsafe.Pointer(prev), unsafe.Pointer(cur)) {
   727  			break
   728  		}
   729  		cnt++
   730  	}
   731  
   732  	return b.String()
   733  }