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 }