{"id":24408832,"url":"https://github.com/sitano/gsysint","last_synced_at":"2025-04-12T02:04:15.176Z","repository":{"id":65624783,"uuid":"57329231","full_name":"sitano/gsysint","owner":"sitano","description":"Golang (as of 1.12.5) runtime internals that gives you an access to internal scheduling primitives. Park Gs, read IDs. (for learning purposes)","archived":false,"fork":false,"pushed_at":"2019-06-07T08:49:44.000Z","size":53,"stargazers_count":69,"open_issues_count":0,"forks_count":9,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-12T02:04:09.920Z","etag":null,"topics":["golang","goroutine","internal","parking","runtime","scheduling"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sitano.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-04-28T19:45:40.000Z","updated_at":"2025-03-30T00:42:46.000Z","dependencies_parsed_at":"2023-02-01T10:25:10.530Z","dependency_job_id":null,"html_url":"https://github.com/sitano/gsysint","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitano%2Fgsysint","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitano%2Fgsysint/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitano%2Fgsysint/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitano%2Fgsysint/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sitano","download_url":"https://codeload.github.com/sitano/gsysint/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248505863,"owners_count":21115354,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","goroutine","internal","parking","runtime","scheduling"],"created_at":"2025-01-20T05:52:58.385Z","updated_at":"2025-04-12T02:04:15.146Z","avatar_url":"https://github.com/sitano.png","language":"C","readme":"# gsysint\n\nGolang (as of 1.12.5) runtime internals that gives you an access to internal scheduling primitives.\n(for learning purposes)\n\nFeatures\n========\n\n* `g` and `m` internal structures access (read goroutine id)\n* goroutines native parking / unparking\n* internal spin lock\n\nExamples\n=======\n\nGet goroutine id:\n\n    g.CurG().GoID\n    \n    or\n    \n    GIDFromStackTrace()\n\nPark goroutine the simple way:\n\n    var p Park\n    p.Set()\n    p.Park(nil)\n    \nPark goroutine detailed (simple):\n\n    w.Add(1)\n    go func() {\n        p.Set()\n        p.Park(nil)\n        w.Done()\n    }()\n    runtime.Gosched()\n    // unpark goroutine and mark as ready\n    p.Ready()\n    w.Wait()\n    \nPark goroutine harder with mutex release on park:\n\n    var gp unsafe.Pointer\n    \n    w := sync.WaitGroup{}\n    w.Add(1)\n    \n    l := \u0026g.Mutex{}\n    go func() {\n        atomic.StorePointer(\u0026gp, g.GetG())\n        Lock(l)\n        // park\n        GoParkUnlock(l, g.WaitReasonZero, trace.TraceEvNone, 1) // actual park\n        w.Done()\n    }()\n\n    runtime.Gosched()\n\n    if gp == nil {\n        t.Fatalf(\"GetG() returned nil pointer to the g structure\")\n    }\n\n    Lock(l)\n    // unpark goroutine and mark as ready\n    GoReady((*g.G)(gp), 1)\n    Unlock(l)\n\n    w.Wait()\n\nScheduling details\n==================\n\nI am not going to cover go [scheduler](\nhttps://github.com/golang/go/blob/7bc40ffb05d8813bf9b41a331b45d37216f9e747/src/runtime/proc.go#L2022)\nin [details](https://golang.org/s/go11sched) here.\n\nThe scheduler's job is to distribute ready-to-run goroutines\nover worker threads. Main concepts:\n\n- G - goroutine.\n- M - worker thread, or machine.\n- P - processor, a resource that is required to execute Go code.\n      M must have an associated P to execute Go code, however it can be\n      blocked or in a syscall w/o an associated P.\n\nRuntime defined as a tuple of (m0, g0). Almost everything interested is happening in\nthe context of g0 (like scheduling, gc setup, etc). Usually switch from an arbitrary\ngoroutine to the g0 can happen in the case of: resceduling, goroutine parking, exiting /\nfinishing, syscalling, recovery from panic and maybe other cases I did not managed\nto find with grep. In order to do a switch runtime calls [mcall](\nhttps://github.com/golang/go/blob/7bc40ffb05d8813bf9b41a331b45d37216f9e747/src/runtime/stubs.go#L34)\nfunction.\n\n`mcall` switches from the g to the g0 stack and invokes fn(g), where g is the\ngoroutine that made the call. mcall can only be called from g stacks (not g0, not gsignal).\n\nParking\n=======\n\nA goroutine can be took off the scheduling for a while to keep resources free until\nsome condition met. It called `parking`. Often and almost always go runtime uses\nthis method to implement various synchronisation primitives behavior and implementation.\n\n* `gopark` puts the current goroutine into a waiting state and calls unlockf.\n  If unlockf returns false, the goroutine is resumed. Implementation execute scheduling\n  of the next goroutine forgetting about existence of current one, until it will\n  be brought back by `goready`. Thus, schedule do not waste resources for goroutines\n  waiting some external event to continue its execution. This used exactly instead\n  of spinning cpu;\n* `goparkunlock` puts the current goroutine into a waiting state and unlocks the lock\n  by calling `parkunlock_c` over internal `mutex` object. If unlockf returns false,\n  the goroutine is resumed. Implemented via;\n* `goready / ready` mark gp ready to run. Naturally `unpark`. Places a goroutine\n  into the next run slot (via `runqput`) or to the local run queue (size 256) if\n  its contended. If the local run queue is full, runnext puts g on the global queue.\n\nParking used in implementations of io, gc, timers, finalizers, channels, panics, tracer,\nsemaphore and select.\n\nIt effectively used for implementations of sync primitives when the moment of acquisition\nor releasing the lock is known in advance (instead of blind spinning) (by some external\nevent i.e.).\n\nIf there was no contention on next run slot on the `p`, `goready` can effectively\nbring goroutine back to life omitting long passing through the run queues what\nintended to minimize latency.\n\nAuthor\n===\n\nIvan Prisyazhnyy, @john.koepi, 2019\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsitano%2Fgsysint","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsitano%2Fgsysint","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsitano%2Fgsysint/lists"}