Category: Software

  • PHP 8.2’s Subtle New Features

    PHP 8.2’s Subtle New Features

    PHP version 8.2 was released on December 8, 2022 and I’m sure you’ve already heard about the great new features. The Randomizer & random generator engines classes, DNF types; constants within traits; the sensitive parameter trait; static return types for dates; the n regular expression modifier; false, true, and null types; the readonly class modifier, a handful of deprecations, and a small performance bump.

    These features are great. They add some new things to play with, fix a few issues, and provide the usual speed boost. What about the more subtle features that aren’t reported on. They need some love too.

    phpinfo()‘s Visual Upgrade

    The first thing I will go over is a feature that doesn’t appear to be reported on anywhere. Not even in the changelog. Why?

    The phpinfo() function got a facelift. It now supports dark mode using the OS and browser’s CSS prefers-color-scheme media query. There is also now sticky headers for tables. The headers will stay at the top of the screen while you continue scrolling.

    Some other new features that go unnoticed…

    • Opimized code path for newly created files using the file:// stream wrapper.
    • Lower memory usage for strings created by various different functions.
    • Added support for curl’s CURLOPT_XFERINFOFUNCTION progress callback option. This replaces the deprecated CURLOPT_PROGRESSFUNCTION option.
    • Added support for curl’s CURLOPT_MAXFILESIZE_LARGE option which sould be used instead of CURLOPT_MAXFILESIZE in cases where the file is greater than 2 gigabytes.
    • Added curl_upkeep(callable) function that accepts a callable (function/method) and is used when HTTP2 keep-alive/ping requests are sent.
    • The idate(format, timestamp) function now supports the “N” and “o” specifiers to get the ISO day of week and ISO year respectively.
    • Added the FILTER_FLAG_GLOBAL_RANGE option when validating with the FILTER_VALIDATE_IP flag in the filter functions. The filter will fail when non-global IPV4/IPV6 IP ranges are used in accordance with RFC 6890 where the Global attribute is false.
    • A number of Apple Mac-specific memory and JIT compiler-related improvements.
    • Added JIT indirect call reduction.
    • Added the openssl_cipher_key_length(algorithm) function.
    • Added the ReflectionFunction::isAnonymous() method which returns true if the function is anonymous (e.g. a closure).
    • Added the ReflectionMethod::hasPrototype() method which returns true if the method has an inherited parent method (prototype).
    • Added a number of new Socket options.
    • Added ini_parse_quantity(string_value) function to convert parsed shorthand ini values that may include a number of supported units to integer value.
    • Added memory_reset_peak_usage() function to allow checking for excess memory usage multiple times throughout a script.

    Upgrade Soon!

    PHP 8.2 has many features that will make development and testing with PHP easier. It’s easy to overlook the more suble and less-reported-on features, but they are often some of the more useful or awaited changes. It’s highly reccomended that you upgrade to version 8.2 soon and always keep your software versions up-to-date to get the latest features and security fixes.

  • Deactivating Troublesome Devices in Linux

    Deactivating Troublesome Devices in Linux

    Sometimes you may run into a situation where a device may not act right. In most cases you can just disable a driver and that works. In other situations, it’s on a controller that handles multiple devices. Disabling a driver will disable multiple devices. So how do you only disabled one specific device without affecting others?

    This happened to me on Linux. My touchpad works fine on Windows, but on Linux… not so much. It works, but I noticed some strange slowness in my system. Looking at top I noticed there were no individual processes using a lot of resources, but one of the CPU’s cores was pegged between 80-98% usage. Ouch.

    I scoured the internet and just got a whole bunch of “find the driver that’s causing the problem and blacklist it” results. I tried that but it also disabled the touchscreen. The touchscreen was not causing a problem… but it was attached to the same serial controller hub.

    Looking at the interrupts I could see that the touchpad, an ELAN (unknown more recent model) was spewing interrupts like a fountain and eating up an entire CPU core:

    Bash
    $ cat /proc/interrupts
    CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7
    1:          0          0          0          0          0          0          0      18400  IR-IO-APIC    1-edge      i8042
    8:          0          0          0          0          0          0          0          0  IR-IO-APIC    8-edge      rtc0
    9:          0         46          0          0          0          0          0          0  IR-IO-APIC    9-fasteoi   acpi
    14:         0          0          0          0          0          0          0          0  IR-IO-APIC   14-fasteoi   INT34C5:00
    16:         0          0          0          0          0       1964          0          0  IR-IO-APIC   16-fasteoi   intel_ish_ipc, i801_smbus
    27:         0       1317          0          0          0          0          0          0  IR-IO-APIC   27-fasteoi   i2c_designware.0, idma64.0
    28:         0         91     392167          0          0          0          0          0  IR-IO-APIC   28-fasteoi
    29:         0          0          0          0          0          0          0          0  IR-IO-APIC   29-fasteoi   i2c_designware.2, idma64.2
    30:         0          0          0          0          0          0          0          0  IR-IO-APIC   30-fasteoi   i2c_designware.3, idma64.3
    43:         0          0          0          0       2212          0          0          0  IR-IO-APIC   43-fasteoi   ELAN9009:00
    57:         0          0          0          1          0          0          0          0  IR-IO-APIC   57-fasteoi
    

    You can see that IRQ 28 was spamming CPU3 with interrupts prior to it being disabled.

    After a lot of digging I found that these ELAN touchpads are notorious for requiring “passcodes” to function properly. Apparently they have a specific “knock” that needs to occur so that they will stop spamming interrupts. The Windows drivers apparently have these knocks. Linux developers either have to guess or try to reverse engineer. Not a high priority for obvious reasons. Linux builders just avoid such devices in computers that will be running Linux.

    How do you match up an interrupt to an address? Not figured that out yet so you might have to do some trial and error on a few devices (it’s pretty easy using the echo function later in this post). If anyone knows how to match an interrupt port to a device address, let me know so I can update this post.

    Bash
    $ lspci -mm
    ...
    00:15.0 "Serial bus controller" "Intel Corporation" "Tiger Lake-LP Serial IO I2C Controller #0" -r20 -p00 "ASUSTeK Computer Inc." "Device 1402"
    00:15.1 "Serial bus controller" "Intel Corporation" "Tiger Lake-LP Serial IO I2C Controller #1" -r20 -p00 "ASUSTeK Computer Inc." "Device 1402"
    00:15.2 "Serial bus controller" "Intel Corporation" "Tiger Lake-LP Serial IO I2C Controller #2" -r20 -p00 "ASUSTeK Computer Inc." "Device 1402"
    00:15.3 "Serial bus controller" "Intel Corporation" "Tiger Lake-LP Serial IO I2C Controller #3" -r20 -p00 "ASUSTeK Computer Inc." "Device 1402"
    ...
    

    Afer some trial-and-error I determined that IRQ 28 was associated with device 00:15.1.

    There had to be a way to disable it while keeping the touchscreen working. After a lot of digging I finally found a 1-line command to disable a specific device by it’s address. But how would I get it to disable every boot? Turns out you can do that via the crontab (you need to be the root user):

    Bash
    $ sudo su
    [sudo] password:
    [root] $ crontab -e
    
    Bash
    @reboot echo "0000:00:15.1" > /sys/bus/pci/devices/0000:00:15.1/driver/unbind
    

    However…

    This is not the best solution. It does run every time the computer is started/restarted, but it happens very late in the boot process. That allows the boot to still get stuck while the part of the CPU is busy trying to handle a flood of interrupts. I needed a way to have it run earlier in the boot process. I discovered an easy way to do just that using a target unit. 💡 The following process is for systemd, if you are using another service manager the process will be different, but should be a similar way to hook into the boot process.

    Target units are scripts that run at a specific point in the boot process. In this case, I run it after sysinit.target, which is the earliest you can run within the boot process. How you do this is by creating a .target file and enable it:

    Bash
    [root] $ edit /usr/lib/systemd/system/disable.device.target
    

    Of course, by edit I mean to use your favorite editor. vim, nano, or any other terminal or graphical editor you wish. Add the following into the file:

    INI
    [Unit]
    Description=Disable Device
    Before=basic.target
    After=local-fs.target sysinit.target
    DefaultDependencies=no
    
    [Service]
    Type=oneshot
    ExecStart=/etc/disable.device.sh
    
    [Install]
    WantedBy=basic.target
    

    You can change where the actual script file is located, I simply picked /etc but you can put it anywhere you wish. Next you need to add the contents of the script. Again, use your favorite editor on /etc/disable.device.sh:

    Bash
    #! /bin/sh
    echo "0000:00:15.1" > /sys/bus/pci/devices/0000:00:15.1/driver/unbind
    

    Then, make sure the script can be executed by the root user:

    Bash
    [root] $ chmod 744 /etc/disable.device.sh
    

    Finally, enable your service:

    Bash
    [root] $ systemctl enable disable.device
    

    That’s it. On the next boot (and every boot after), the device will automatically be disabled early in the boot process.