Skip to content

Conversation

@tslmy
Copy link

@tslmy tslmy commented Nov 29, 2025

Tested working on an iPod touch (4th gen) running iOS 6.1.6:

process information IO information
image image

How to build

Prerequisites:

  • macOS with Homebrew. Tested on macOS 15.7.2 (24G325).
  • Xcode 4.6.3 DMG mounted at /Volumes/Xcode.
  • automake (brew install automake)
  • ncurses (brew install ncurses)

Prepare the SDK

htop needs the IOKit framework for probing battery, disk I/O, and GPU statuses. The vanilla iPhoneOS6.1 SDK does not provide headers for IOKit, so we'll have to stitch together a Frankenstein-style SDK for getting around it.

Assuming you are at a directory outside of htop codebase:

set -gx FOO "/Volumes/Xcode/Xcode.app/Contents/Developer/Platforms"
cp -r $FOO/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk .
cp -r $FOO/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.1.sdk/System/Library/Frameworks/IOKit.framework/Versions/A/Headers iPhoneOS6.1.sdk/System/Library/Frameworks/IOKit.framework/
cp $FOO/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/IOKit.framework/Versions/A/Headers/storage/IOBlockStorageDriver.h iPhoneOS6.1.sdk/System/Library/Frameworks/IOKit.framework/Headers/storage/

Don't unmount the Xcode DMG just yet; we still need the simulator's SDK (for libproc.h).

Build

Assuming you are now in the htop directory, here's the full commands needed to build:

set -gx IOS6_SDK_PATH "/path/to/the/frankenstein/sdk/above/iPhoneOS6.1.sdk"

./autogen.sh
./configure \
  --host=armv7-apple-darwin \
  --disable-unicode \
  --disable-sensors \
  --disable-hwloc \
  CFLAGS="-arch armv7 \
        -miphoneos-version-min=6.1 \
        -isysroot $IOS6_SDK_PATH \
        -I/Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.1.sdk/usr/include \
        -I/opt/homebrew/opt/ncurses/include"
make

@BenBE BenBE added the MacOS 🍏 MacOS / Darwin related issues label Nov 29, 2025
@Explorer09
Copy link
Contributor

While this thing might work, the fact that it's generated suggests we cannot merge it as is. Because there's no human review, and there is a copyright concern (the AI might have copied code from someone else that is unlicensed).

Putting the general issue of AI-generated code aside, i see there's a massive style violation. We're not defining or using a macro token like TARGET_OS_IPHONE. Besides, the missing libraries and headers in iPhone should be addressed with configure script macros. So a AC_CHECK_HEADERS(libproc.h) call and a substitute header ProvideLibproc.h might be a good way to start.

Copy link
Member

@BenBE BenBE left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are several issues with this implementation, in particular with the feature availability checking, which should best be done using configure checks.

Also, given that the proc_taskinfo structure is allocated on the stack, we should be VERY careful, that we are not mixing ABI boundaries with libproc (which doesn't exist for iPhone 6, but might for later models). Thus ensure, that you only ever have this structure defined when using your own code for accessing proc_taskinfo-related stuff OR know you are using the structure definition that comes from the libproc you are calling.

And now for the elephant in the room: While there is no general ban of AI generated code per se, we still require for contributions to include proper attribution for all (non-trivial) source code copied (or adapted) from other places. An example for this in your PR is with the proc_taskinfo struct (and some other stub types you define), but this also includes magic values like IFT_LOOP, RTM_IFINFO2, AT_FDCWD, AT_SYMLINK_NOFOLLOW,

You should be able to provide a valid and qualified Developer Certificate of Origin alongside with your code, which ATM is not the case (due to the insufficiently attributed third-party sources).

@tslmy
Copy link
Author

tslmy commented Nov 29, 2025

Thank you @BenBE and @Explorer09 for the very detailed reviews! Let me address them and get back to you. Putting this to draft mode while I'm at it.

Is there unit tests that I can run?

@tslmy tslmy marked this pull request as draft November 29, 2025 18:22
Comment on lines 426 to 435
#if !TARGET_OS_IPHONE /* iOS 6.1 SDK doesn't have compressor_page_count and external_page_count */
natural_t used = vm->active_count + vm->inactive_count +
vm->speculative_count + vm->wire_count +
vm->compressor_page_count - vm->purgeable_count - vm->external_page_count;
mtr->values[MEMORY_METER_USED] = (double)(used - vm->compressor_page_count) * page_K;
#else
natural_t used = vm->active_count + vm->inactive_count +
vm->speculative_count + vm->wire_count - vm->purgeable_count;
mtr->values[MEMORY_METER_USED] = (double)used * page_K;
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nonexistent fields should be better checked in configure.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This overall nesting of ifdef checks is hard to red overall. A better approach might be needed.

@BenBE
Copy link
Member

BenBE commented Nov 29, 2025

Please note the instruction regarding rebasing/amending your commits for PRs in the style guide.

@tslmy
Copy link
Author

tslmy commented Nov 30, 2025 via email

@tslmy tslmy marked this pull request as ready for review November 30, 2025 10:33
@tslmy tslmy requested review from BenBE and Explorer09 November 30, 2025 10:33
@tslmy tslmy changed the title [feat] Add support for iOS 6.1.x [feat] Add basic support for iOS 6.1 Nov 30, 2025
@Explorer09
Copy link
Contributor

The entire PR has become too messy for me to review further. There are still coding style violations here and there. But it seems like there are some compatibility fixes that can be cherry-picked early (such as the check of struct vm_statistics64.compressor_page_count).

@BenBE
Copy link
Member

BenBE commented Nov 30, 2025

Dear @Explorer09,

Please keep discussion in here civilized.

If you don't like AI-generated code: Fine.

If someone has no experience with a certain tool: Help them to get to know that tool or point them to resources that provide an introduction or explain necessary concepts.

If code doesn't follow the coding style: Explain the issue and provide possible alternatives.

BUT: This is no place for attacks or personal vendettas against any particular technology, just because someone chooses to use them.

This is voluntary work. Nobody forces you to respond to each and every issue/PR.

@tslmy
Copy link
Author

tslmy commented Nov 30, 2025

I'm sorry you feel this way @Explorer09 . Please take a break and you're welcome back when you feel better.

To both of you @Explorer09 and @BenBE :

Thanks for the reviews again. Let me put this PR to draft mode again while I'm at it. (I might need to pick this up only at a next weekend, though.)

In general, I'm a bit confused about the "code style" that you all have been referring to. I thought those changes are applied automatically, yet I don't see a pre-commit hook or a CI job kicking in.

I've been treating the code style doc as "hey don't be surprised if we modify your code this way eventually / don't be offended when a script keeps formatting your code this way", but judging from your comments this isn't the case.

Are those code style rules to be followed manually?

@tslmy tslmy marked this pull request as draft November 30, 2025 17:05
@Explorer09
Copy link
Contributor

@tslmy

In general, I'm a bit confused about the "code style" that you all have been referring to. I thought those changes are applied automatically, yet I don't see a pre-commit hook or a CI job kicking in.

I've been treating the code style doc as "hey don't be surprised if we modify your code this way eventually / don't be offended when a script keeps formatting your code this way", but judging from your comments this isn't the case.

Are those code style rules to be followed manually?

Some code style cannot be automated prior to commit, and our attitude to pull requests is that: it is the OP's responsibility to code in our style when proposing code changes. If someone cannot bother to adapt to our code style, then it's better to maintain htop in their fork and not propose upstream.

Significant disruption to code style and/or paradigms can complicate other developers when reviewing your code. And note that I only review htop PRs on the voluntary basis - and it would be unpleasant for me if someone seems to be deliberately wasting my time.

@tslmy tslmy marked this pull request as draft November 30, 2025 20:00
@Explorer09
Copy link
Contributor

And no: There is no commit hook magically fixing things. Writing well structured code is the responsibility of the developer – even if they decide to support their work with tools like code formatters (like astyle) or AI agents.

While automated code style fixing tools can correct the line breaking, indents and token spacing, there are many things that would be off the scope of said tools: Variable or function naming, choice on whether to define a constant as a macro or enum, the overall code structure in a header or source file, etc.

Therefore, don't expect there would be a tool, AI powered or not, that magically fixes everything.

@tslmy tslmy force-pushed the ios6 branch 2 times, most recently from 0b64c08 to dc1b54e Compare December 1, 2025 02:31
@tslmy tslmy marked this pull request as ready for review December 1, 2025 02:35
@tslmy
Copy link
Author

tslmy commented Dec 1, 2025

Hi all,

What a journey!

This Frankenstein-style SDK worked better than I expected (🤦 ). It inspired me to use iPhone Simulator's SDK files for this libproc support, so I don't even need XNU now. This PR has now boiled down to just 4 small patches, which I've re-organized as atomic commits.

I guess this "simulator SDK will help a lot" is common knowledge to the jailbreak community 🤷 . But when it comes to learning something, later is better than never! :D

I appreciate you all guiding me through this weekend hobbyist project of mine, as I'm quite amateur when it comes to htop codebase itself, open-source C programs in general, and iOS/Mach/XNU development. 🫡

Compat.c Outdated
#endif

#ifndef AT_SYMLINK_NOFOLLOW
# define AT_SYMLINK_NOFOLLOW 0x100
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can we be sure every OS define AT_FDCWD and AT_SYMLINK_NOFOLLOW to the same value? Both constant values seem to be internal to the OS.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's actually a good point. I simply saw the code above

/* GNU/Hurd does not have PATH_MAX in limits.h */
#ifndef PATH_MAX
# define PATH_MAX 4096
#endif

and assumed hardcoding platform-specific constants is acceptable here at htop.

I've surrounded these two constants with #ifdef __APPLE__. That should be just safe enough.

Copy link
Contributor

@Explorer09 Explorer09 Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tslmy For limit constants it's okay to define it to an arbitrary value as long as it's a common denominator across all OSes.

Not the case for constants that are used for option flags. Even you can define them, chances are the flags won't work, or worse, it might enable some undocumented feature of that OS's API that could wreak havoc.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's fair. For now I'll just leave the two statements guarded by #ifdef __APPLE__. I'll wait and see what CI says (assuming our test suite covers this).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth taking a step back here - the Compat functions using these macros are only used on Linux (same is true for xReadfileat AFAICT). A simpler fix may involve moving these things into the linux/ subdirectory so that they're not compiled at all on on darwin (or anywhere else).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Explorer09 :

Can you examine why in iOS 6 AT_FDCWD and AT_SYMLINK_NOFOLLOW are undefined? This doesn't look normal

I think there's an important distinction to make here: iOS the software itself and the iOS SDK.

I believe it is defined in iOS 6's source code itself (as deep down as XNU); it's just that it's not exposed to us developers in its official SDK.

iOS isn't known for its openness back in the 2010s. It doesn't really surprise me that Apple decided to not expose current working directory (AT_FDCWD) to developers.

That said, when it comes to AT_SYMLINK_NOFOLLOW, there's actually a counterpart in iPhoneOS6.1.sdk/usr/include/sys/fcntl.h:

#define O_NOFOLLOW  0x0100      /* don't follow symlinks */

The bottom line: reusing the values defined in XNU is still the best idea I have so far 🤷

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@natoscott :

I hear you. Honestly I didn't know /proc was a Linux-specific thing (TIL a lot). I'm not very confident dealing with the clean-up just yet -- still on my warm-up reps here. Do you think we can find someone more experienced in FreeBSD & Linux development to look at it, or could you wait till I make another PR dedicated for this next weekend?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tslmy leave it with me, I'll see if this approach is feasible tomorrow.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tslmy it worked out nicely - #1832 - you can drop those changes to Compat.h once this is merged.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome. Thanks!

used += vm->compressor_page_count;
mtr->values[MEMORY_METER_USED] = (double)(used - vm->compressor_page_count) * page_K;
#else
mtr->values[MEMORY_METER_USED] = (double)used * page_K;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A separate mtr->values[MEMORY_METER_USED] assignment line doesn't look right.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, there are already two branches. To avoid assigning again, I'll have to introduce a new variable:

@@ -401,6 +401,7 @@
    const struct vm_statistics* vm = &dhost->vm_stats;
 #endif
    double page_K = (double)vm_page_size / (double)1024;
+   double usedPages = 0.0;
 
    mtr->total = dhost->host_info.max_mem / 1024;
 #ifdef HAVE_STRUCT_VM_STATISTICS64
@@ -411,13 +412,14 @@
 #endif
 #ifdef HAVE_STRUCT_VM_STATISTICS64_COMPRESSOR_PAGE_COUNT
    used += vm->compressor_page_count;
-   mtr->values[MEMORY_METER_USED] = (double)(used - vm->compressor_page_count) * page_K;
+   usedPages = (double)(used - vm->compressor_page_count);
 #else
-   mtr->values[MEMORY_METER_USED] = (double)used * page_K;
+   usedPages = (double)used;
 #endif
 #else
-   mtr->values[MEMORY_METER_USED] = (double)(vm->active_count + vm->wire_count) * page_K;
+   usedPages = (double)(vm->active_count + vm->wire_count);
 #endif
+   mtr->values[MEMORY_METER_USED] = usedPages * page_K;
    // mtr->values[MEMORY_METER_SHARED] = "shared memory, like tmpfs and shm"
 #ifdef HAVE_STRUCT_VM_STATISTICS64
 #ifdef HAVE_STRUCT_VM_STATISTICS64_COMPRESSOR_PAGE_COUNT

which doesn't look too elegant to me. What do you say?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, it might be good to examine why there were two branches in the first place. Ideally the formula for counting "used" memory shouldn't differ between 32-bits and 64-bits.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like Apple Silicon support (731812d), perhaps something to do with Unified Memory if I'm reading it right.

That said, it's not yet clear to me how to unify all three branches together.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to sort out the amount of used/external/compressed memory first, before assigning. The external and compressed memory should be restricted to cases where they are provided by the OS, thus in these cases modifying the used value should be trivial in the appropriate branches. After that's done, updating the mtr->values[MEMORY_METER_USED] should be straight forward.

It furthermore helps to limit nesting things to the bare minimum.

@tslmy
Copy link
Author

tslmy commented Dec 1, 2025

Turns out the deprecated name (*master*) is now caught as an error when building for modern macOS.

I've force-pushed again to make use of

#if __IPHONE_OS_VERSION_MIN_REQUIRED <= __IPHONE_6_1

as a stricter way to apply the patches. When building for iOS, this macro is needed anyway.

I can put this in configure, but another part of me doesn't want to expose this macro to all other platforms.

@tslmy tslmy force-pushed the ios6 branch 2 times, most recently from 8cf5d91 to f608416 Compare December 2, 2025 00:08
natoscott added a commit to natoscott/htop that referenced this pull request Dec 2, 2025
Transition Compat.[ch] into the Linux platform directory.
Linux is the only platform using this code after several
years now so best if its not compiled into all the other
platforms htop binary.  However, this change is primarily
intended to assist with the iOS port.

Related: htop-dev#1828
natoscott added a commit to natoscott/htop that referenced this pull request Dec 2, 2025
Transition Compat.[ch] into the Linux platform directory.
Linux is the only platform using this code after several
years now so best if its not compiled into all the other
platforms htop binary.  However, this change is primarily
intended to assist with the iOS port.

Related: htop-dev#1828
@tslmy tslmy requested a review from BenBE December 4, 2025 22:15
mchlyu pushed a commit to mchlyu/htop that referenced this pull request Dec 23, 2025
Transition Compat.[ch] into the Linux platform directory.
Linux is the only platform using this code after several
years now so best if its not compiled into all the other
platforms htop binary.  However, this change is primarily
intended to assist with the iOS port.

Related: htop-dev#1828
Copy link
Member

@BenBE BenBE left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor note on the commit messages: The common format is a short subject line, with optional explanatory text following after a blank.

So a message like

Handle when external/compressed page counts are unavailable

Some SDKs (especially older ones like iPhoneOS 6.1) do not expose …

read much cleaner. Similar:

Handle legacy references to kIOMainPortDefault

In old SDKs kIOMainPortDefault was originally called kIOMasterPortDefault.
Handling this legacy name allows for support of old SDKs like iPhoneOS 6.1.

And lastly:

Handle include order constraints

Some old SDKs (e.g. for iPhoneOS 6.1) require includes to be ordered such
that header net/if.h is included after sys/socket.h

Speaking of which: mach/port.h should appear after unistd.h, unless there's a constraint on that one too (unrelated to your patch, but can be cleaned up when we are touching there anyways; separate commit "Clean up include order" please).

#include "zfs/ZfsArcStats.h"

// Compatibility for older SDKs.
#if defined(HAVE_DECL_KIOMAINPORTDEFAULT) && !HAVE_DECL_KIOMAINPORTDEFAULT
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be

Suggested change
#if defined(HAVE_DECL_KIOMAINPORTDEFAULT) && !HAVE_DECL_KIOMAINPORTDEFAULT
#if !defined(HAVE_DECL_KIOMAINPORTDEFAULT) || !HAVE_DECL_KIOMAINPORTDEFAULT

used += vm->compressor_page_count;
mtr->values[MEMORY_METER_USED] = (double)(used - vm->compressor_page_count) * page_K;
#else
mtr->values[MEMORY_METER_USED] = (double)used * page_K;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to sort out the amount of used/external/compressed memory first, before assigning. The external and compressed memory should be restricted to cases where they are provided by the OS, thus in these cases modifying the used value should be trivial in the appropriate branches. After that's done, updating the mtr->values[MEMORY_METER_USED] should be straight forward.

It furthermore helps to limit nesting things to the bare minimum.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

MacOS 🍏 MacOS / Darwin related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants