@@ -2251,6 +2251,136 @@ uint64_t uv_get_available_memory(void) {
2251
2251
}
2252
2252
2253
2253
2254
+ static int uv__get_cgroupv2_constrained_cpu (const char * cgroup ,
2255
+ uv__cpu_constraint * constraint ) {
2256
+ char path [256 ];
2257
+ char buf [1024 ];
2258
+ unsigned int weight ;
2259
+ int cgroup_size ;
2260
+ const char * cgroup_trimmed ;
2261
+ char quota_buf [16 ];
2262
+
2263
+ if (strncmp (cgroup , "0::/" , 4 ) != 0 )
2264
+ return UV_EINVAL ;
2265
+
2266
+ /* Trim ending \n by replacing it with a 0 */
2267
+ cgroup_trimmed = cgroup + sizeof ("0::/" ) - 1 ; /* Skip the prefix "0::/" */
2268
+ cgroup_size = (int )strcspn (cgroup_trimmed , "\n" ); /* Find the first slash */
2269
+
2270
+ /* Construct the path to the cpu.max file */
2271
+ snprintf (path , sizeof (path ), "/sys/fs/cgroup/%.*s/cpu.max" , cgroup_size ,
2272
+ cgroup_trimmed );
2273
+
2274
+ /* Read cpu.max */
2275
+ if (uv__slurp (path , buf , sizeof (buf )) < 0 )
2276
+ return UV_EIO ;
2277
+
2278
+ if (sscanf (buf , "%15s %llu" , quota_buf , & constraint -> period_length ) != 2 )
2279
+ return UV_EINVAL ;
2280
+
2281
+ if (strncmp (quota_buf , "max" , 3 ) == 0 )
2282
+ constraint -> quota_per_period = LLONG_MAX ;
2283
+ else if (sscanf (quota_buf , "%lld" , & constraint -> quota_per_period ) != 1 )
2284
+ return UV_EINVAL ; // conversion failed
2285
+
2286
+ /* Construct the path to the cpu.weight file */
2287
+ snprintf (path , sizeof (path ), "/sys/fs/cgroup/%.*s/cpu.weight" , cgroup_size ,
2288
+ cgroup_trimmed );
2289
+
2290
+ /* Read cpu.weight */
2291
+ if (uv__slurp (path , buf , sizeof (buf )) < 0 )
2292
+ return UV_EIO ;
2293
+
2294
+ if (sscanf (buf , "%u" , & weight ) != 1 )
2295
+ return UV_EINVAL ;
2296
+
2297
+ constraint -> proportions = (double )weight / 100.0 ;
2298
+
2299
+ return 0 ;
2300
+ }
2301
+
2302
+ static char * uv__cgroup1_find_cpu_controller (const char * cgroup ,
2303
+ int * cgroup_size ) {
2304
+ /* Seek to the cpu controller line. */
2305
+ char * cgroup_cpu = strstr (cgroup , ":cpu," );
2306
+
2307
+ if (cgroup_cpu != NULL ) {
2308
+ /* Skip the controller prefix to the start of the cgroup path. */
2309
+ cgroup_cpu += sizeof (":cpu," ) - 1 ;
2310
+ /* Determine the length of the cgroup path, excluding the newline. */
2311
+ * cgroup_size = (int )strcspn (cgroup_cpu , "\n" );
2312
+ }
2313
+
2314
+ return cgroup_cpu ;
2315
+ }
2316
+
2317
+ static int uv__get_cgroupv1_constrained_cpu (const char * cgroup ,
2318
+ uv__cpu_constraint * constraint ) {
2319
+ char path [256 ];
2320
+ char buf [1024 ];
2321
+ unsigned int shares ;
2322
+ int cgroup_size ;
2323
+ char * cgroup_cpu ;
2324
+
2325
+ cgroup_cpu = uv__cgroup1_find_cpu_controller (cgroup , & cgroup_size );
2326
+
2327
+ if (cgroup_cpu == NULL )
2328
+ return UV_EIO ;
2329
+
2330
+ /* Construct the path to the cpu.cfs_quota_us file */
2331
+ snprintf (path , sizeof (path ), "/sys/fs/cgroup/%.*s/cpu.cfs_quota_us" ,
2332
+ cgroup_size , cgroup_cpu );
2333
+
2334
+ if (uv__slurp (path , buf , sizeof (buf )) < 0 )
2335
+ return UV_EIO ;
2336
+
2337
+ if (sscanf (buf , "%lld" , & constraint -> quota_per_period ) != 1 )
2338
+ return UV_EINVAL ;
2339
+
2340
+ /* Construct the path to the cpu.cfs_period_us file */
2341
+ snprintf (path , sizeof (path ), "/sys/fs/cgroup/%.*s/cpu.cfs_period_us" ,
2342
+ cgroup_size , cgroup_cpu );
2343
+
2344
+ /* Read cpu.cfs_period_us */
2345
+ if (uv__slurp (path , buf , sizeof (buf )) < 0 )
2346
+ return UV_EIO ;
2347
+
2348
+ if (sscanf (buf , "%lld" , & constraint -> period_length ) != 1 )
2349
+ return UV_EINVAL ;
2350
+
2351
+ /* Construct the path to the cpu.shares file */
2352
+ snprintf (path , sizeof (path ), "/sys/fs/cgroup/%.*s/cpu.shares" , cgroup_size ,
2353
+ cgroup_cpu );
2354
+
2355
+ /* Read cpu.shares */
2356
+ if (uv__slurp (path , buf , sizeof (buf )) < 0 )
2357
+ return UV_EIO ;
2358
+
2359
+ if (sscanf (buf , "%u" , & shares ) != 1 )
2360
+ return UV_EINVAL ;
2361
+
2362
+ constraint -> proportions = (double )shares / 1024.0 ;
2363
+
2364
+ return 0 ;
2365
+ }
2366
+
2367
+ int uv__get_constrained_cpu (uv__cpu_constraint * constraint ) {
2368
+ char cgroup [1024 ];
2369
+
2370
+ /* Read the cgroup from /proc/self/cgroup */
2371
+ if (uv__slurp ("/proc/self/cgroup" , cgroup , sizeof (cgroup )) < 0 )
2372
+ return UV_EIO ;
2373
+
2374
+ /* Check if the system is using cgroup v2 by examining /proc/self/cgroup
2375
+ * The entry for cgroup v2 is always in the format "0::$PATH"
2376
+ * see https://docs.kernel.org/admin-guide/cgroup-v2.html */
2377
+ if (strncmp (cgroup , "0::/" , 4 ) == 0 )
2378
+ return uv__get_cgroupv2_constrained_cpu (cgroup , constraint );
2379
+ else
2380
+ return uv__get_cgroupv1_constrained_cpu (cgroup , constraint );
2381
+ }
2382
+
2383
+
2254
2384
void uv_loadavg (double avg [3 ]) {
2255
2385
struct sysinfo info ;
2256
2386
char buf [128 ]; /* Large enough to hold all of /proc/loadavg. */
0 commit comments