smartpointer.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. package frankenphp
  2. // #include <stdlib.h>
  3. import "C"
  4. import (
  5. "runtime/cgo"
  6. "unsafe"
  7. )
  8. /*
  9. FrankenPHP is fairly complex because it shuffles handles/requests/contexts
  10. between C and Go. This simplifies the lifecycle management of per-request
  11. structures by allowing us to hold references until the end of the request
  12. and ensure they are always cleaned up.
  13. */
  14. // PointerList A list of pointers that can be freed at a later time
  15. type pointerList struct {
  16. Pointers []unsafe.Pointer
  17. }
  18. // HandleList A list of pointers that can be freed at a later time
  19. type handleList struct {
  20. Handles []cgo.Handle
  21. }
  22. // AddHandle Call when registering a handle for the very first time
  23. func (h *handleList) AddHandle(handle cgo.Handle) {
  24. h.Handles = append(h.Handles, handle)
  25. }
  26. // AddPointer Call when creating a request-level C pointer for the very first time
  27. func (p *pointerList) AddPointer(ptr unsafe.Pointer) {
  28. p.Pointers = append(p.Pointers, ptr)
  29. }
  30. // AddString adds a string to the pointer list by converting it to a C-char pointer and calling the AddPointer method.
  31. // The string is converted to a C-char pointer using the C.CString function.
  32. // It is recommended to use this method when you need to add a string to the pointer list.
  33. func (p *pointerList) AddString(str *C.char) {
  34. p.AddPointer(unsafe.Pointer(str))
  35. //getLogger().Warn("Adding string", zap.Int("i", len(p.Pointers)), zap.String("str", C.GoString(str)), zap.Stack("trace"))
  36. }
  37. // ToCString takes a string and converts it to a C string using C.CString. Then it calls the AddString method of
  38. // pointerList to add the resulting C string as a pointer to the pointer
  39. func (p *pointerList) ToCString(string string) *C.char {
  40. str := C.CString(string)
  41. p.AddString(str)
  42. return str
  43. }
  44. // FreeAll frees all C pointers
  45. func (p *pointerList) FreeAll() {
  46. for _, ptr := range p.Pointers {
  47. //getLogger().Warn("About to delete", zap.Int("i", i))
  48. C.free(ptr)
  49. }
  50. p.Pointers = nil // To avoid dangling pointers
  51. }
  52. // FreeAll frees all handles
  53. func (h *handleList) FreeAll() {
  54. for _, p := range h.Handles {
  55. p.Delete()
  56. }
  57. }
  58. // Pointers Get a new list of pointers
  59. func Pointers() *pointerList {
  60. return &pointerList{
  61. Pointers: make([]unsafe.Pointer, 0),
  62. }
  63. }
  64. // Handles Get a new list of handles
  65. func Handles() *handleList {
  66. return &handleList{
  67. Handles: make([]cgo.Handle, 0, 8),
  68. }
  69. }